1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)package org.chromium.content.browser;
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.content.Context;
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.os.Bundle;
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import android.os.SystemClock;
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.util.Log;
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)import android.view.InputDevice;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.MotionEvent;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import android.view.ViewConfiguration;
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.chromium.base.CommandLine;
16f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.chromium.content.browser.LongPressDetector.LongPressDelegate;
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.browser.third_party.GestureDetector;
184e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import org.chromium.content.browser.third_party.GestureDetector.OnDoubleTapListener;
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import org.chromium.content.browser.third_party.GestureDetector.OnGestureListener;
20f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)import org.chromium.content.common.ContentSwitches;
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import org.chromium.content.common.TraceEvent;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.ArrayDeque;
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import java.util.Deque;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)/**
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * This class handles all MotionEvent handling done in ContentViewCore including the gesture
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) * recognition. It sends all related native calls through the interface MotionEventDelegate.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) */
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ContentViewGestureHandler implements LongPressDelegate {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    private static final String TAG = "ContentViewGestureHandler";
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used for GESTURE_FLING_START x velocity
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String VELOCITY_X = "Velocity X";
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used for GESTURE_FLING_START y velocity
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String VELOCITY_Y = "Velocity Y";
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used for GESTURE_SCROLL_BY x distance
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String DISTANCE_X = "Distance X";
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used for GESTURE_SCROLL_BY y distance
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String DISTANCE_Y = "Distance Y";
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used in GESTURE_SINGLE_TAP_CONFIRMED to check whether ShowPress has been called before.
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String SHOW_PRESS = "ShowPress";
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used for GESTURE_PINCH_BY delta
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final String DELTA = "Delta";
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
58f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
59f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * Used by UMA stat for tracking accidental double tap navigations. Specifies the amount of
60f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * time after a double tap within which actions will be recorded to the UMA stat.
61f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
62f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private static final long ACTION_AFTER_DOUBLE_TAP_WINDOW_MS = 5000;
63f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Bundle mExtraParamBundleSingleTap;
65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Bundle mExtraParamBundleFling;
66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Bundle mExtraParamBundleScroll;
67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Bundle mExtraParamBundleDoubleTapDragZoom;
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    private final Bundle mExtraParamBundlePinchBy;
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private GestureDetector mGestureDetector;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final ZoomManager mZoomManager;
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private LongPressDetector mLongPressDetector;
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private OnGestureListener mListener;
734e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private OnDoubleTapListener mDoubleTapListener;
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private MotionEvent mCurrentDownEvent;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private final MotionEventDelegate mMotionEventDelegate;
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Queue of motion events.
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private final Deque<MotionEvent> mPendingMotionEvents = new ArrayDeque<MotionEvent>();
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // All events are forwarded to the GestureDetector, bypassing Javascript.
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int NO_TOUCH_HANDLER = 0;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // All events are forwarded as normal to Javascript, and if unconsumed to the GestureDetector.
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //     * Activated from the renderer by way of |hasTouchEventHandlers(true)|.
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int HAS_TOUCH_HANDLER = 1;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Events in the current gesture are forwarded to the GestureDetector, bypassing Javascript.
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //     * Activated if the touch down for the current gesture had no Javascript consumer.
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int NO_TOUCH_HANDLER_FOR_GESTURE = 2;
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // Events in the current gesture are forwarded to Javascript, and not to the GestureDetector.
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    //     * Activated if *any* touch event in the current sequence was consumed by Javascript.
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int JAVASCRIPT_CONSUMING_GESTURE = 3;
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private static final int TOUCH_HANDLING_STATE_DEFAULT = NO_TOUCH_HANDLER;
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    private int mTouchHandlingState = TOUCH_HANDLING_STATE_DEFAULT;
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Remember whether onShowPress() is called. If it is not, in onSingleTapConfirmed()
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // we will first show the press state, then trigger the click.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean mShowPressIsCalled;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
103f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Whether a sent GESTURE_TAP_DOWN event has yet to be accompanied by a corresponding
104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // GESTURE_SINGLE_TAP_UP, GESTURE_SINGLE_TAP_CONFIRMED, GESTURE_TAP_CANCEL or
105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // GESTURE_DOUBLE_TAP.
106f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private boolean mNeedsTapEndingEvent;
107f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // This flag is used for ignoring the remaining touch events, i.e., All the events until the
1093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // next ACTION_DOWN. This is automatically set to false on the next ACTION_DOWN.
1103551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    private boolean mIgnoreRemainingTouchEvents;
1113551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // TODO(klobag): this is to avoid a bug in GestureDetector. With multi-touch,
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // mAlwaysInTapRegion is not reset. So when the last finger is up, onSingleTapUp()
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // will be mistakenly fired.
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean mIgnoreSingleTap;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
117bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // True from right before we send the first scroll event until the last finger is raised.
118bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    private boolean mTouchScrolling;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
120bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // TODO(wangxianzhu): For now it is true after a fling is started until the next
121bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // touch. Should reset it to false on end of fling if the UI is able to know when the
122bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    // fling ends.
123b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    private boolean mFlingMayBeActive;
124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private boolean mSeenFirstScrollEvent;
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean mPinchInProgress = false;
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    //On single tap this will store the x, y coordinates of the touch.
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int mSingleTapX;
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int mSingleTapY;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    // Indicate current double tap mode state.
1364e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private int mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
1377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // x, y coordinates for an Anchor on double tap drag zoom.
1397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private float mDoubleTapDragZoomAnchorX;
1407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private float mDoubleTapDragZoomAnchorY;
1417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // On double tap this will store the y coordinates of the touch.
1437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private float mDoubleTapY;
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    // Double tap drag zoom sensitive (speed).
1467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private static final float DOUBLE_TAP_DRAG_ZOOM_SPEED = 0.005f;
1477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Used to track the last rawX/Y coordinates for moves.  This gives absolute scroll distance.
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Useful for full screen tracking.
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private float mLastRawX = 0;
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private float mLastRawY = 0;
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Cache of square of the scaled touch slop so we don't have to calculate it on every touch.
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private int mScaledTouchSlopSquare;
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // Object that keeps track of and updates scroll snapping behavior.
157f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private final SnapScrollController mSnapScrollController;
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Used to track the accumulated scroll error over time. This is used to remove the
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // rounding error we introduced by passing integers to webkit.
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private float mAccumulatedScrollErrorX = 0;
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private float mAccumulatedScrollErrorY = 0;
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1640f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // The page's viewport and scale sometimes allow us to disable double tap gesture detection,
1650f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    // according to the logic in ContentViewCore.onRenderCoordinatesUpdated().
1660f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    private boolean mShouldDisableDoubleTap;
1674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
168d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    // Keeps track of the last long press event, if we end up opening a context menu, we would need
169f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // to potentially use the event to send GESTURE_TAP_CANCEL to remove ::active styling
170d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    private MotionEvent mLastLongPressEvent;
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1721e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    // Whether the click delay should always be disabled by sending clicks for double tap gestures.
1731e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private final boolean mDisableClickDelay;
1741e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
175f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Used for tracking UMA ActionAfterDoubleTap to tell user's immediate
176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // action after a double tap.
177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private long mLastDoubleTapTimeMs;
178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final int GESTURE_SHOW_PRESSED_STATE = 0;
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final int GESTURE_DOUBLE_TAP = 1;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final int GESTURE_SINGLE_TAP_UP = 2;
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    static final int GESTURE_SINGLE_TAP_CONFIRMED = 3;
183b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_SINGLE_TAP_UNCONFIRMED = 4;
184b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_LONG_PRESS = 5;
185b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_SCROLL_START = 6;
186b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_SCROLL_BY = 7;
187b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_SCROLL_END = 8;
188b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_FLING_START = 9;
189b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_FLING_CANCEL = 10;
190b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_PINCH_BEGIN = 11;
191b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_PINCH_BY = 12;
192b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_PINCH_END = 13;
193f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static final int GESTURE_TAP_CANCEL = 14;
194b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)    static final int GESTURE_LONG_TAP = 15;
1951e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    static final int GESTURE_TAP_DOWN = 16;
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // These have to be kept in sync with content/port/common/input_event_ack_state.h
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static final int INPUT_EVENT_ACK_STATE_UNKNOWN = 0;
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static final int INPUT_EVENT_ACK_STATE_CONSUMED = 1;
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static final int INPUT_EVENT_ACK_STATE_NOT_CONSUMED = 2;
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    static final int INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS = 3;
202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static final int INPUT_EVENT_ACK_STATE_IGNORED = 4;
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2049ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    // Return values of sendPendingEventToNative();
205c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    static final int EVENT_FORWARDED_TO_NATIVE = 0;
206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    static final int EVENT_DROPPED = 1;
207c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    static final int EVENT_NOT_FORWARDED = 2;
208c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private final float mPxToDp;
2107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2114e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    static final int DOUBLE_TAP_MODE_NONE = 0;
2124e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    static final int DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS = 1;
2134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    static final int DOUBLE_TAP_MODE_DRAG_ZOOM = 2;
2144e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    static final int DOUBLE_TAP_MODE_DISABLED = 3;
2157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * This is an interface to handle MotionEvent related communication with the native side also
2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * access some ContentView specific parameters.
2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public interface MotionEventDelegate {
2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Send a raw {@link MotionEvent} to the native side
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param timeMs Time of the event in ms.
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param action The action type for the event.
2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param pts The TouchPoint array to be sent for the event.
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return Whether the event was sent to the native side successfully or not.
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts);
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        /**
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Send a gesture event to the native side.
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param type The type of the gesture event.
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param timeMs The time the gesture event occurred at.
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param x The x location for the gesture event.
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param y The y location for the gesture event.
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @param extraParams A bundle that holds specific extra parameters for certain gestures.
237424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)         *                    This is read-only and should not be modified in this function.
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Refer to gesture type definition for more information.
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * @return Whether the gesture was sent successfully.
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
24158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        boolean sendGesture(int type, long timeMs, int x, int y, Bundle extraParams);
24258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
24358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        /**
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         * Show the zoom picker UI.
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)         */
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        public void invokeZoomPicker();
247f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
248f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        /**
249f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         * Send action after dobule tap for UMA stat tracking.
250f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         * @param type The action that occured
251f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         * @param clickDelayEnabled Whether the tap down delay is active
252f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         */
253f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        public void sendActionAfterDoubleTapUMA(int type, boolean clickDelayEnabled);
254f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
255f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        /**
256f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         * Send single tap UMA.
257f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         * @param type The tap type: delayed or undelayed
258f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)         */
259f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        public void sendSingleTapUMA(int type);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ContentViewGestureHandler(
263f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            Context context, MotionEventDelegate delegate, ZoomManager zoomManager) {
264424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleSingleTap = new Bundle();
265424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleFling = new Bundle();
266424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleScroll = new Bundle();
267424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleDoubleTapDragZoom = new Bundle();
268424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundlePinchBy = new Bundle();
269424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mLongPressDetector = new LongPressDetector(context, this);
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mMotionEventDelegate = delegate;
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mZoomManager = zoomManager;
273c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        mSnapScrollController = new SnapScrollController(context, mZoomManager);
2747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        mPxToDp = 1.0f / context.getResources().getDisplayMetrics().density;
275c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2761e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        mDisableClickDelay = CommandLine.isInitialized() &&
277f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                CommandLine.getInstance().hasSwitch(ContentSwitches.DISABLE_CLICK_DELAY);
2781e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        initGestureDetectors(context);
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Used to override the default long press detector, gesture detector and listener.
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * This is used for testing only.
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param longPressDetector The new LongPressDetector to be assigned.
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param gestureDetector The new GestureDetector to be assigned.
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param listener The new onGestureListener to be assigned.
2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void setTestDependencies(
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            LongPressDetector longPressDetector, GestureDetector gestureDetector,
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            OnGestureListener listener) {
292d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (longPressDetector != null) mLongPressDetector = longPressDetector;
293d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (gestureDetector != null) mGestureDetector = gestureDetector;
294d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (listener != null) mListener = listener;
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void initGestureDetectors(final Context context) {
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        final int scaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mScaledTouchSlopSquare = scaledTouchSlop * scaledTouchSlop;
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TraceEvent.begin();
3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            GestureDetector.SimpleOnGestureListener listener =
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                new GestureDetector.SimpleOnGestureListener() {
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public boolean onDown(MotionEvent e) {
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mShowPressIsCalled = false;
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mIgnoreSingleTap = false;
308bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                        mTouchScrolling = false;
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        mSeenFirstScrollEvent = false;
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        mSnapScrollController.resetSnapScrollMode();
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mLastRawX = e.getRawX();
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mLastRawY = e.getRawY();
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mAccumulatedScrollErrorX = 0;
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mAccumulatedScrollErrorY = 0;
315f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        mNeedsTapEndingEvent = false;
316f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        if (sendMotionEventAsGesture(GESTURE_TAP_DOWN, e, null)) {
317f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            mNeedsTapEndingEvent = true;
318f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        }
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // Return true to indicate that we want to handle touch
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return true;
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public boolean onScroll(MotionEvent e1, MotionEvent e2,
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            float distanceX, float distanceY) {
3261e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        assert e1.getEventTime() <= e2.getEventTime();
327c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        if (!mSeenFirstScrollEvent) {
328c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            // Remove the touch slop region from the first scroll event to avoid a
329c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            // jump.
330c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            mSeenFirstScrollEvent = true;
331c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            double distance = Math.sqrt(
332c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                    distanceX * distanceX + distanceY * distanceY);
333c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            double epsilon = 1e-3;
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            if (distance > epsilon) {
335c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                double ratio = Math.max(0, distance - scaledTouchSlop) / distance;
336c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                distanceX *= ratio;
337c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                distanceY *= ratio;
338c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            }
339c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        }
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        mSnapScrollController.updateSnapScrollMode(distanceX, distanceY);
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        if (mSnapScrollController.isSnappingScrolls()) {
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            if (mSnapScrollController.isSnapHorizontal()) {
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                distanceY = 0;
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            } else {
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                distanceX = 0;
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            }
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mLastRawX = e2.getRawX();
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mLastRawY = e2.getRawY();
351bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                        if (!mTouchScrolling) {
352f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            sendTapCancelIfNecessary(e1);
353bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                            endFlingIfNecessary(e2.getEventTime());
3541e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                            if (sendGesture(GESTURE_SCROLL_START, e2.getEventTime(),
3551e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                                        (int) e1.getX(), (int) e1.getY(), null)) {
356bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                                mTouchScrolling = true;
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            }
3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // distanceX and distanceY is the scrolling offset since last onScroll.
3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // Because we are passing integers to webkit, this could introduce
3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // rounding errors. The rounding errors will accumulate overtime.
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // To solve this, we should be adding back the rounding errors each time
3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // when we calculate the new offset.
3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int x = (int) e2.getX();
3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int y = (int) e2.getY();
3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int dx = (int) (distanceX + mAccumulatedScrollErrorX);
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int dy = (int) (distanceY + mAccumulatedScrollErrorY);
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mAccumulatedScrollErrorX = distanceX + mAccumulatedScrollErrorX - dx;
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mAccumulatedScrollErrorY = distanceY + mAccumulatedScrollErrorY - dy;
370424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
371424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        mExtraParamBundleScroll.putInt(DISTANCE_X, dx);
372424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        mExtraParamBundleScroll.putInt(DISTANCE_Y, dy);
373424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        assert mExtraParamBundleScroll.size() == 2;
374424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        if ((dx | dy) != 0) {
376f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            sendGesture(GESTURE_SCROLL_BY,
377424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                    e2.getEventTime(), x, y, mExtraParamBundleScroll);
3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mMotionEventDelegate.invokeZoomPicker();
3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return true;
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public boolean onFling(MotionEvent e1, MotionEvent e2,
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            float velocityX, float velocityY) {
3881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                        assert e1.getEventTime() <= e2.getEventTime();
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        if (mSnapScrollController.isSnappingScrolls()) {
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            if (mSnapScrollController.isSnapHorizontal()) {
3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                velocityY = 0;
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            } else {
3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                velocityX = 0;
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            }
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
397f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        fling(e2.getEventTime(), (int) e1.getX(0), (int) e1.getY(0),
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                        (int) velocityX, (int) velocityY);
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return true;
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public void onShowPress(MotionEvent e) {
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        mShowPressIsCalled = true;
405c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        sendMotionEventAsGesture(GESTURE_SHOW_PRESSED_STATE, e, null);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public boolean onSingleTapUp(MotionEvent e) {
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        if (isDistanceBetweenDownAndUpTooLong(e.getRawX(), e.getRawY())) {
411f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                            sendTapCancelIfNecessary(e);
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            mIgnoreSingleTap = true;
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            return true;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // This is a hack to address the issue where user hovers
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // over a link for longer than DOUBLE_TAP_TIMEOUT, then
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // onSingleTapConfirmed() is not triggered. But we still
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // want to trigger the tap event at UP. So we override
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // onSingleTapUp() in this case. This assumes singleTapUp
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // gets always called before singleTapConfirmed.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        if (!mIgnoreSingleTap && !mLongPressDetector.isInLongPress()) {
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            if (e.getEventTime() - e.getDownTime() > DOUBLE_TAP_TIMEOUT) {
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                float x = e.getX();
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                float y = e.getY();
425f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                if (sendTapEndingEventAsGesture(GESTURE_SINGLE_TAP_UP, e, null)) {
4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    mIgnoreSingleTap = true;
4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                }
4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                setClickXAndY((int) x, (int) y);
429f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
430f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                mMotionEventDelegate.sendSingleTapUMA(
431f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                        isDoubleTapDisabled() ?
432f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                        ContentViewCore.UMASingleTapType.UNDELAYED_TAP :
433f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                        ContentViewCore.UMASingleTapType.DELAYED_TAP);
434f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                return true;
4361e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)                            } else if (isDoubleTapDisabled() || mDisableClickDelay) {
4374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                // If double tap has been disabled, there is no need to wait
4384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                // for the double tap timeout.
4394e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                return onSingleTapConfirmed(e);
440b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                            } else {
441b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                // Notify Blink about this tapUp event anyway,
442b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                // when none of the above conditions applied.
443b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                                sendMotionEventAsGesture(GESTURE_SINGLE_TAP_UNCONFIRMED, e, null);
4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                            }
4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                        return triggerLongTapIfNeeded(e);
4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public boolean onSingleTapConfirmed(MotionEvent e) {
4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // Long taps in the edges of the screen have their events delayed by
4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // ContentViewHolder for tab swipe operations. As a consequence of the delay
4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // this method might be called after receiving the up event.
4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        // These corner cases should be ignored.
4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        if (mLongPressDetector.isInLongPress() || mIgnoreSingleTap) return true;
4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
458f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        mMotionEventDelegate.sendSingleTapUMA(
459f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                isDoubleTapDisabled() ?
460f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                ContentViewCore.UMASingleTapType.UNDELAYED_TAP :
461f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                ContentViewCore.UMASingleTapType.DELAYED_TAP);
462f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int x = (int) e.getX();
4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        int y = (int) e.getY();
465424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        mExtraParamBundleSingleTap.putBoolean(SHOW_PRESS, mShowPressIsCalled);
466424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                        assert mExtraParamBundleSingleTap.size() == 1;
467f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                        if (sendTapEndingEventAsGesture(GESTURE_SINGLE_TAP_CONFIRMED, e,
4684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                mExtraParamBundleSingleTap)) {
4694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                            mIgnoreSingleTap = true;
4704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                        }
471424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)
4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        setClickXAndY(x, y);
4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return true;
4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
4777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    public boolean onDoubleTapEvent(MotionEvent e) {
4787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        switch (e.getActionMasked()) {
4797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            case MotionEvent.ACTION_DOWN:
480f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                sendTapCancelIfNecessary(e);
4817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                mDoubleTapDragZoomAnchorX = e.getX();
4827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                mDoubleTapDragZoomAnchorY = e.getY();
4834e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                mDoubleTapMode = DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS;
4847dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                break;
4857dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            case MotionEvent.ACTION_MOVE:
4864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                if (mDoubleTapMode
4874e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        == DOUBLE_TAP_MODE_DRAG_DETECTION_IN_PROGRESS) {
4887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    float distanceX = mDoubleTapDragZoomAnchorX - e.getX();
4897dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    float distanceY = mDoubleTapDragZoomAnchorY - e.getY();
4907dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
4917dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    // Begin double tap drag zoom mode if the move distance is
4927dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    // further than the threshold.
4937dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    if (distanceX * distanceX + distanceY * distanceY >
4947dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            mScaledTouchSlopSquare) {
495f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                        sendTapCancelIfNecessary(e);
4967dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                        sendGesture(GESTURE_SCROLL_START, e.getEventTime(),
4977dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                (int) e.getX(), (int) e.getY(), null);
4987dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                        pinchBegin(e.getEventTime(),
4997dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                Math.round(mDoubleTapDragZoomAnchorX),
5007dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                Math.round(mDoubleTapDragZoomAnchorY));
5014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                        mDoubleTapMode = DOUBLE_TAP_MODE_DRAG_ZOOM;
5027dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    }
5034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                } else if (mDoubleTapMode == DOUBLE_TAP_MODE_DRAG_ZOOM) {
504424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                    assert mExtraParamBundleDoubleTapDragZoom.isEmpty();
5057dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    sendGesture(GESTURE_SCROLL_BY, e.getEventTime(),
506424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                            (int) e.getX(), (int) e.getY(),
507424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)                                            mExtraParamBundleDoubleTapDragZoom);
5087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
5097dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    float dy = mDoubleTapY - e.getY();
5107dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    pinchBy(e.getEventTime(),
5117dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            Math.round(mDoubleTapDragZoomAnchorX),
5127dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                            Math.round(mDoubleTapDragZoomAnchorY),
51368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                            (float) Math.pow(dy > 0 ?
5147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                    1.0f - DOUBLE_TAP_DRAG_ZOOM_SPEED :
5157dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                    1.0f + DOUBLE_TAP_DRAG_ZOOM_SPEED,
5167dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                                    Math.abs(dy * mPxToDp)));
5177dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                }
5187dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                break;
5197dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            case MotionEvent.ACTION_UP:
5204e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                if (mDoubleTapMode != DOUBLE_TAP_MODE_DRAG_ZOOM) {
5217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                    // Normal double tap gesture.
522f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                    sendTapEndingEventAsGesture(GESTURE_DOUBLE_TAP, e, null);
5237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                }
5244e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                endDoubleTapDragIfNecessary(e);
5257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                break;
5267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            case MotionEvent.ACTION_CANCEL:
527f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                                sendTapCancelIfNecessary(e);
5284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                endDoubleTapDragIfNecessary(e);
5297dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                break;
5307dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                            default:
5317dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                break;
5327dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        }
5337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        mDoubleTapY = e.getY();
5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return true;
5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    @Override
5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    public void onLongPress(MotionEvent e) {
5397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                        if (!mZoomManager.isScaleGestureDetectionInProgress() &&
5404e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                (mDoubleTapMode == DOUBLE_TAP_MODE_NONE ||
5414e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                                 isDoubleTapDisabled())) {
542d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                            mLastLongPressEvent = e;
543c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                            sendMotionEventAsGesture(GESTURE_LONG_PRESS, e, null);
5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        }
5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    /**
5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * This method inspects the distance between where the user started touching
5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * the surface, and where she released. If the points are too far apart, we
5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * should assume that the web page has consumed the scroll-events in-between,
5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * and as such, this should not be considered a single-tap.
5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     *
5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * We use the Android frameworks notion of how far a touch can wander before
5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * we think the user is scrolling.
5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     *
5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * @param x the new x coordinate
5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * @param y the new y coordinate
5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     * @return true if the distance is too long to be considered a single tap
5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                     */
5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    private boolean isDistanceBetweenDownAndUpTooLong(float x, float y) {
5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        double deltaX = mLastRawX - x;
5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        double deltaY = mLastRawY - y;
5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        return deltaX * deltaX + deltaY * deltaY > mScaledTouchSlopSquare;
5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    }
5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                };
566f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mListener = listener;
567f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mDoubleTapListener = listener;
568f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mGestureDetector = new GestureDetector(context, listener);
569f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mGestureDetector.setIsLongpressEnabled(false);
5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } finally {
5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TraceEvent.end();
5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return LongPressDetector handling setting up timers for and canceling LongPress gestures.
5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LongPressDetector getLongPressDetector() {
5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mLongPressDetector;
5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param event Start a LongPress gesture event from the listener.
5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    @Override
5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public void onLongPress(MotionEvent event) {
5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mListener.onLongPress(event);
5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Cancels any ongoing LongPress timers.
5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void cancelLongPress() {
5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mLongPressDetector.cancelLongPress();
5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Fling the ContentView from the current position.
5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param x Fling touch starting position
6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param y Fling touch starting position
6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param velocityX Initial velocity of the fling (X) measured in pixels per second.
6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param velocityY Initial velocity of the fling (Y) measured in pixels per second.
6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void fling(long timeMs, int x, int y, int velocityX, int velocityY) {
605bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        endFlingIfNecessary(timeMs);
60668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
60768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        if (velocityX == 0 && velocityY == 0) {
60868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            endTouchScrollIfNecessary(timeMs, true);
60968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)            return;
61068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)        }
61168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
612bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (!mTouchScrolling) {
613c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // The native side needs a GESTURE_SCROLL_BEGIN before GESTURE_FLING_START
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // to send the fling to the correct target. Send if it has not sent.
615c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            sendGesture(GESTURE_SCROLL_START, timeMs, x, y, null);
616c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        }
617bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        endTouchScrollIfNecessary(timeMs, false);
618c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
619b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)        mFlingMayBeActive = true;
620b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
621424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleFling.putInt(VELOCITY_X, velocityX);
622424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundleFling.putInt(VELOCITY_Y, velocityY);
623424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        assert mExtraParamBundleFling.size() == 2;
624424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        sendGesture(GESTURE_FLING_START, timeMs, x, y, mExtraParamBundleFling);
6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
628bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     * Send a GESTURE_FLING_CANCEL event if necessary.
6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param timeMs The time in ms for the event initiating this gesture.
6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
631bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    void endFlingIfNecessary(long timeMs) {
632bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (!mFlingMayBeActive) return;
633bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        mFlingMayBeActive = false;
634bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        sendGesture(GESTURE_FLING_CANCEL, timeMs, 0, 0, null);
6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    /**
6384e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * End DOUBLE_TAP_MODE_DRAG_ZOOM by sending GESTURE_SCROLL_END and GESTURE_PINCH_END events.
6397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     * @param event A hint event that its x, y, and eventTime will be used for the ending events
6407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     *              to send. This argument is an optional and can be null.
6417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch     */
6424e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    void endDoubleTapDragIfNecessary(MotionEvent event) {
6431e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        if (!isDoubleTapActive()) return;
6444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (mDoubleTapMode == DOUBLE_TAP_MODE_DRAG_ZOOM) {
6457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            if (event == null) event = obtainActionCancelMotionEvent();
6467dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            pinchEnd(event.getEventTime());
6477dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            sendGesture(GESTURE_SCROLL_END, event.getEventTime(),
6487dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    (int) event.getX(), (int) event.getY(), null);
6497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        }
6504e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        mDoubleTapMode = DOUBLE_TAP_MODE_NONE;
6511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        updateDoubleTapListener();
6527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
6537dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
654bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    /**
655bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     * Reset touch scroll flag and optionally send a GESTURE_SCROLL_END event if necessary.
656bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     * @param timeMs The time in ms for the event initiating this gesture.
657bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     * @param sendScrollEndEvent Whether to send GESTURE_SCROLL_END event.
658bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     */
659bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch    private void endTouchScrollIfNecessary(long timeMs, boolean sendScrollEndEvent) {
660bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (!mTouchScrolling) return;
661bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        mTouchScrolling = false;
662bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        if (sendScrollEndEvent) {
663bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch            sendGesture(GESTURE_SCROLL_END, timeMs, 0, 0, null);
6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
668bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch     * @return Whether native is tracking a scroll.
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    boolean isNativeScrolling() {
671bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        // TODO(wangxianzhu): Also return true when fling is active once the UI knows exactly when
672bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        // the fling ends.
673bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch        return mTouchScrolling;
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return Whether native is tracking a pinch (i.e. between sending GESTURE_PINCH_BEGIN and
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     *         GESTURE_PINCH_END).
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    boolean isNativePinching() {
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return mPinchInProgress;
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Starts a pinch gesture.
6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param timeMs The time in ms for the event initiating this gesture.
6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param x The x coordinate for the event initiating this gesture.
6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param y The x coordinate for the event initiating this gesture.
6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void pinchBegin(long timeMs, int x, int y) {
691c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        sendGesture(GESTURE_PINCH_BEGIN, timeMs, x, y, null);
6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Pinch by a given percentage.
6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param timeMs The time in ms for the event initiating this gesture.
6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param anchorX The x coordinate for the anchor point to be used in pinch.
6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param anchorY The y coordinate for the anchor point to be used in pinch.
6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param delta The percentage to pinch by.
7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void pinchBy(long timeMs, int anchorX, int anchorY, float delta) {
702424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mExtraParamBundlePinchBy.putFloat(DELTA, delta);
703424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        assert mExtraParamBundlePinchBy.size() == 1;
704f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        sendGesture(GESTURE_PINCH_BY, timeMs, anchorX, anchorY, mExtraParamBundlePinchBy);
7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mPinchInProgress = true;
7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * End a pinch gesture.
7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @param timeMs The time in ms for the event initiating this gesture.
7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void pinchEnd(long timeMs) {
713c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        sendGesture(GESTURE_PINCH_END, timeMs, 0, 0, null);
7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mPinchInProgress = false;
7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Ignore singleTap gestures.
7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void setIgnoreSingleTap(boolean value) {
7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mIgnoreSingleTap = value;
7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private void setClickXAndY(int x, int y) {
7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSingleTapX = x;
7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mSingleTapY = y;
7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return The x coordinate for the last point that a singleTap gesture was initiated from.
7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int getSingleTapX()  {
7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mSingleTapX;
7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return The y coordinate for the last point that a singleTap gesture was initiated from.
7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    public int getSingleTapY()  {
7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return mSingleTapY;
7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
7443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * Cancel the current touch event sequence by sending ACTION_CANCEL and ignore all the
7453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * subsequent events until the next ACTION_DOWN.
7463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     *
7473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     * One example usecase is stop processing the touch events when showing context popup menu.
7483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)     */
7493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    public void setIgnoreRemainingTouchEvents() {
7503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        onTouchEvent(obtainActionCancelMotionEvent());
7513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)        mIgnoreRemainingTouchEvents = true;
7523551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
7533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    /**
7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Handle the incoming MotionEvent.
7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return Whether the event was handled.
7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    boolean onTouchEvent(MotionEvent event) {
7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        try {
7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TraceEvent.begin("onTouchEvent");
7613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            if (mIgnoreRemainingTouchEvents) {
7633551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
7643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    mIgnoreRemainingTouchEvents = false;
7653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                } else {
7663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                    return false;
7673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)                }
7683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)            }
7693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            mLongPressDetector.cancelLongPressIfNeeded(event);
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mSnapScrollController.setSnapScrollingMode(event);
7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Notify native that scrolling has stopped whenever a down action is processed prior to
7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // passing the event to native as it will drop them as an optimization if scrolling is
7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // enabled.  Ending the fling ensures scrolling has stopped as well as terminating the
7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // current fling if applicable.
7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
777bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch                endFlingIfNecessary(event.getEventTime());
7787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            } else if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN) {
7794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                endDoubleTapDragIfNecessary(null);
7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            if (offerTouchEventToJavaScript(event)) {
7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                // offerTouchEventToJavaScript returns true to indicate the event was sent
7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                // to the render process. If it is not subsequently handled, it will
7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                // be returned via confirmTouchEvent(false) and eventually passed to
7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                // processTouchEvent asynchronously.
7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return true;
7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            return processTouchEvent(event);
7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        } finally {
7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            TraceEvent.end("onTouchEvent");
7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
795d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    /**
796d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     * Handle content view losing focus -- ensure that any remaining active state is removed.
797d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)     */
798d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    void onWindowFocusLost() {
799d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        if (mLongPressDetector.isInLongPress() && mLastLongPressEvent != null) {
800f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            sendTapCancelIfNecessary(mLastLongPressEvent);
801d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)        }
802d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    }
803d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private MotionEvent obtainActionCancelMotionEvent() {
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return MotionEvent.obtain(
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                SystemClock.uptimeMillis(),
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                SystemClock.uptimeMillis(),
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                MotionEvent.ACTION_CANCEL, 0.0f,  0.0f,  0);
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Resets gesture handlers state; called on didStartLoading().
8132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Note that this does NOT clear the pending motion events queue;
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * it gets cleared in hasTouchEventHandlers() called from WebKit
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * FrameLoader::transitionToCommitted iff the page ever had touch handlers.
8162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
8172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void resetGestureHandlers() {
818424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        MotionEvent me = obtainActionCancelMotionEvent();
819424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        me.setSource(InputDevice.SOURCE_CLASS_POINTER);
820424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mGestureDetector.onTouchEvent(me);
821424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        mZoomManager.processTouchEvent(me);
822424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)        me.recycle();
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mLongPressDetector.cancelLongPress();
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Sets the flag indicating that the content has registered listeners for touch events.
8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void hasTouchEventHandlers(boolean hasTouchHandlers) {
830a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (hasTouchHandlers) {
831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // If no touch handler was previously registered, ensure that we
832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // don't send a partial gesture to Javascript.
833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (mTouchHandlingState == NO_TOUCH_HANDLER)
834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                mTouchHandlingState = NO_TOUCH_HANDLER_FOR_GESTURE;
835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        } else {
836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // When mainframe is loading, FrameLoader::transitionToCommitted will
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // call this method with |hasTouchHandlers| of false. We use this as
838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // an indicator to clear the pending motion events so that events from
839a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            // the previous page will not be carried over to the new page.
840a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mTouchHandlingState = NO_TOUCH_HANDLER;
841a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mPendingMotionEvents.clear();
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean offerTouchEventToJavaScript(MotionEvent event) {
846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (mTouchHandlingState == NO_TOUCH_HANDLER) return false;
8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            // Avoid flooding the renderer process with move events: if the previous pending
8507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            // command is also a move (common case) that has not yet been forwarded, skip sending
8517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            //  this event to the webkit side and collapse it into the pending event.
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            MotionEvent previousEvent = mPendingMotionEvents.peekLast();
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (previousEvent != null
8547dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                    && previousEvent != mPendingMotionEvents.peekFirst()
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    && previousEvent.getActionMasked() == MotionEvent.ACTION_MOVE
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                    && previousEvent.getPointerCount() == event.getPointerCount()) {
8577dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                TraceEvent.instant("offerTouchEventToJavaScript:EventCoalesced",
8587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                                   "QueueSize = " + mPendingMotionEvents.size());
8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                MotionEvent.PointerCoords[] coords =
860c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                        new MotionEvent.PointerCoords[event.getPointerCount()];
8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                for (int i = 0; i < coords.length; ++i) {
8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    coords[i] = new MotionEvent.PointerCoords();
8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    event.getPointerCoords(i, coords[i]);
8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                }
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                previousEvent.addBatch(event.getEventTime(), coords, event.getMetaState());
8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                return true;
8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
869c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        if (mPendingMotionEvents.isEmpty()) {
8709ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            // Add the event to the pending queue prior to calling sendPendingEventToNative.
871868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // When sending an event to native, the callback to confirmTouchEvent can be
872868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // synchronous or asynchronous and confirmTouchEvent expects the event to be
873868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            // in the queue when it is called.
874868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            MotionEvent clone = MotionEvent.obtain(event);
875868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            mPendingMotionEvents.add(clone);
876868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
8779ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            int forward = sendPendingEventToNative();
878f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (forward != EVENT_FORWARDED_TO_NATIVE) mPendingMotionEvents.remove(clone);
879868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)            return forward != EVENT_NOT_FORWARDED;
880868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        } else {
8817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            TraceEvent.instant("offerTouchEventToJavaScript:EventQueued",
8827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                               "QueueSize = " + mPendingMotionEvents.size());
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // Copy the event, as the original may get mutated after this method returns.
884c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            MotionEvent clone = MotionEvent.obtain(event);
885c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            mPendingMotionEvents.add(clone);
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return true;
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
8909ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    private int sendPendingEventToNative() {
8919ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        MotionEvent event = mPendingMotionEvents.peekFirst();
8929ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        if (event == null) {
8939ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            assert false : "Cannot send from an empty pending event queue";
8949ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            return EVENT_NOT_FORWARDED;
8959ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        }
896a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mTouchHandlingState != NO_TOUCH_HANDLER;
8979ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
898a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // The start of a new (multi)touch sequence will reset the touch handling state, and
899a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        // should always be offered to Javascript (when there is any touch handler).
900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (event.getActionMasked() == MotionEvent.ACTION_DOWN) {
901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            mTouchHandlingState = HAS_TOUCH_HANDLER;
90281d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch            if (mCurrentDownEvent != null) recycleEvent(mCurrentDownEvent);
90381d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch            mCurrentDownEvent = null;
904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        }
905868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
906f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mLongPressDetector.onOfferTouchEventToJavaScript(event);
907f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        if (mTouchHandlingState == NO_TOUCH_HANDLER_FOR_GESTURE) return EVENT_NOT_FORWARDED;
909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
910f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (event.getActionMasked() == MotionEvent.ACTION_MOVE) {
911f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            // If javascript has not yet prevent-defaulted the touch sequence,
912f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            // only send move events if the move has exceeded the slop threshold.
913f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            boolean moveEventConfirmed =
914f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    mLongPressDetector.confirmOfferMoveEventToJavaScript(event);
915a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE
916a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    && !moveEventConfirmed) {
917f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                return EVENT_DROPPED;
918f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
919f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
920f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
92181d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch        if (mTouchScrolling || mPinchInProgress) return EVENT_NOT_FORWARDED;
92281d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch
9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        TouchPoint[] pts = new TouchPoint[event.getPointerCount()];
9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        int type = TouchPoint.createTouchPoints(event, pts);
925c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
926868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        if (type == TouchPoint.CONVERSION_ERROR) return EVENT_NOT_FORWARDED;
927868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
92881d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch        if (mMotionEventDelegate.sendTouchEvent(event.getEventTime(), type, pts)) {
92981d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch            return EVENT_FORWARDED_TO_NATIVE;
9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
931c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return EVENT_NOT_FORWARDED;
9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    private boolean processTouchEvent(MotionEvent event) {
9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        boolean handled = false;
9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // The last "finger up" is an end to scrolling but may not be
9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // an end to movement (e.g. fling scroll).  We do not tell
9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // native code to end scrolling until we are sure we did not
9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // fling.
9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        boolean possiblyEndMovement = false;
9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // "Last finger raised" could be an end to movement.  However,
9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // give the mSimpleTouchDetector a chance to continue
9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // scrolling with a fling.
9444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (event.getAction() == MotionEvent.ACTION_UP
9454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                || event.getAction() == MotionEvent.ACTION_CANCEL) {
946bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch            if (mTouchScrolling) {
9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                possiblyEndMovement = true;
9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            }
9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mLongPressDetector.cancelLongPressIfNeeded(event);
9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        mLongPressDetector.startLongPressTimerIfNeeded(event);
9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // Use the framework's GestureDetector to detect pans and zooms not already
9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        // handled by the WebKit touch events gesture manager.
9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (canHandle(event)) {
9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)            handled |= mGestureDetector.onTouchEvent(event);
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            if (event.getAction() == MotionEvent.ACTION_DOWN) {
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                mCurrentDownEvent = MotionEvent.obtain(event);
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            }
9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        handled |= mZoomManager.processTouchEvent(event);
9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        if (possiblyEndMovement && !handled) {
966bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch            endTouchScrollIfNecessary(event.getEventTime(), true);
9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return handled;
9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * Respond to a MotionEvent being returned from the native side.
974868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)     * @param ackResult The status acknowledgment code.
9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    void confirmTouchEvent(int ackResult) {
97758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        try {
97858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            TraceEvent.begin("confirmTouchEvent");
9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
98058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            if (mPendingMotionEvents.isEmpty()) {
98158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                Log.w(TAG, "confirmTouchEvent with Empty pending list!");
98258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                return;
98358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
984a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mTouchHandlingState != NO_TOUCH_HANDLER;
985a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            assert mTouchHandlingState != NO_TOUCH_HANDLER_FOR_GESTURE;
9862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
98758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            MotionEvent ackedEvent = mPendingMotionEvents.removeFirst();
98858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            switch (ackResult) {
98958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case INPUT_EVENT_ACK_STATE_UNKNOWN:
99058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    // This should never get sent.
991f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    assert (false);
99258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
99358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case INPUT_EVENT_ACK_STATE_CONSUMED:
994f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                case INPUT_EVENT_ACK_STATE_IGNORED:
99581d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                    if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE
99681d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                            && ackedEvent.getActionMasked() != MotionEvent.ACTION_DOWN) {
99781d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                        sendTapCancelIfNecessary(ackedEvent);
99881d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                        resetGestureHandlers();
99981d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                    } else {
100081d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                        mZoomManager.passTouchEventThrough(ackedEvent);
100181d04fa4ca6b8e7c49e7a3401149aa77d5b4f381Ben Murdoch                    }
1002a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    mTouchHandlingState = JAVASCRIPT_CONSUMING_GESTURE;
100358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    trySendPendingEventsToNative();
100458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
100558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case INPUT_EVENT_ACK_STATE_NOT_CONSUMED:
1006a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE) {
1007a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        processTouchEvent(ackedEvent);
1008a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    }
100958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    trySendPendingEventsToNative();
101058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
101158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                case INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS:
1012a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE) {
1013a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        processTouchEvent(ackedEvent);
1014a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    }
1015a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    if (ackedEvent.getActionMasked() == MotionEvent.ACTION_DOWN) {
1016a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        drainAllPendingEventsUntilNextDown();
1017a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    } else {
1018a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        trySendPendingEventsToNative();
1019a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    }
102058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
102158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                default:
102258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                    break;
102358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            }
102458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
102558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            mLongPressDetector.cancelLongPressIfNeeded(mPendingMotionEvents.iterator());
102658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            recycleEvent(ackedEvent);
102758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        } finally {
102858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            TraceEvent.end("confirmTouchEvent");
102958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        }
10302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10329ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    private void trySendPendingEventsToNative() {
10337dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        while (!mPendingMotionEvents.isEmpty()) {
10349ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            int forward = sendPendingEventToNative();
1035f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            if (forward == EVENT_FORWARDED_TO_NATIVE) break;
10362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1037c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            // Even though we missed sending one event to native, as long as we haven't
10382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // received INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS, we should keep sending
10392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            // events on the queue to native.
10409ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            MotionEvent event = mPendingMotionEvents.removeFirst();
1041a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            if (mTouchHandlingState != JAVASCRIPT_CONSUMING_GESTURE
1042a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                    && forward != EVENT_DROPPED) {
1043f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                processTouchEvent(event);
1044f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            }
10459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch            recycleEvent(event);
10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        }
10472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    private void drainAllPendingEventsUntilNextDown() {
1050a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        assert mTouchHandlingState == HAS_TOUCH_HANDLER;
1051a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        mTouchHandlingState = NO_TOUCH_HANDLER_FOR_GESTURE;
1052a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
10532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        // Now process all events that are in the queue until the next down event.
10542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        MotionEvent nextEvent = mPendingMotionEvents.peekFirst();
10552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        while (nextEvent != null && nextEvent.getActionMasked() != MotionEvent.ACTION_DOWN) {
10562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            processTouchEvent(nextEvent);
10572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            mPendingMotionEvents.removeFirst();
10587dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch            recycleEvent(nextEvent);
10592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            nextEvent = mPendingMotionEvents.peekFirst();
10602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
10612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
10629ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch        trySendPendingEventsToNative();
10637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    }
10647dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
10657dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    private void recycleEvent(MotionEvent event) {
10667dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch        event.recycle();
1067c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1068c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1069c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private boolean sendMotionEventAsGesture(
1070c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            int type, MotionEvent event, Bundle extraParams) {
1071f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return sendGesture(type, event.getEventTime(),
107258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)            (int) event.getX(), (int) event.getY(), extraParams);
1073c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
1074c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1075c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    private boolean sendGesture(
1076c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            int type, long timeMs, int x, int y, Bundle extraParams) {
1077f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        assert timeMs != 0;
1078f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        updateDoubleTapUmaTimer();
1079f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1080f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (type == GESTURE_DOUBLE_TAP) reportDoubleTap();
1081c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
108258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        return mMotionEventDelegate.sendGesture(type, timeMs, x, y, extraParams);
10832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
10842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1085f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private boolean sendTapEndingEventAsGesture(int type, MotionEvent e, Bundle extraParams) {
1086f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (!sendMotionEventAsGesture(type, e, extraParams)) return false;
1087f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mNeedsTapEndingEvent = false;
1088f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return true;
1089f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
10902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1091f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private void sendTapCancelIfNecessary(MotionEvent e) {
1092f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (!mNeedsTapEndingEvent) return;
1093f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (!sendTapEndingEventAsGesture(GESTURE_TAP_CANCEL, e, null)) return;
1094f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mLastLongPressEvent = null;
10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    /**
10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * @return Whether the ContentViewGestureHandler can handle a MotionEvent right now. True only
10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     * if it's the start of a new stream (ACTION_DOWN), or a continuation of the current stream.
11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)     */
11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    boolean canHandle(MotionEvent ev) {
11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return ev.getAction() == MotionEvent.ACTION_DOWN ||
11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                (mCurrentDownEvent != null && mCurrentDownEvent.getDownTime() == ev.getDownTime());
11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
11062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
11072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return Whether the event can trigger a LONG_TAP gesture. True when it can and the event
11082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * will be consumed.
11092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
11102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    boolean triggerLongTapIfNeeded(MotionEvent ev) {
11112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (mLongPressDetector.isInLongPress() && ev.getAction() == MotionEvent.ACTION_UP &&
11122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                !mZoomManager.isScaleGestureDetectionInProgress()) {
1113f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            sendTapCancelIfNecessary(ev);
1114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)            sendMotionEventAsGesture(GESTURE_LONG_TAP, ev, null);
11152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            return true;
11162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        }
11172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return false;
11182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
11212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * This is for testing only.
11222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return The first motion event on the pending motion events queue.
11232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    MotionEvent peekFirstInPendingMotionEventsForTesting() {
11252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return mPendingMotionEvents.peekFirst();
11262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
11292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * This is for testing only.
11302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * @return The number of motion events on the pending motion events queue.
11312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int getNumberOfPendingMotionEventsForTesting() {
11332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        return mPendingMotionEvents.size();
11342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    /**
11372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * This is for testing only.
11382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * Sends a show pressed state gesture through mListener. This should always be called after
11392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     * a down event;
11402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)     */
1141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    void sendShowPressedStateGestureForTesting() {
11422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        if (mCurrentDownEvent == null) return;
11432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        mListener.onShowPress(mCurrentDownEvent);
11442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
11459ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
11469ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    /**
11479ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch     * This is for testing only.
1148f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @return Whether a sent TapDown event has been accompanied by a tap-ending event.
1149f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
1150f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    boolean needsTapEndingEventForTesting() {
1151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        return mNeedsTapEndingEvent;
1152f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1153f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1154f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
11554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * Update whether double-tap gestures are supported. This allows
11560f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * double-tap gesture suppression independent of whether or not the page's
11570f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * viewport and scale would normally prevent double-tap.
11584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * Note: This should never be called while a double-tap gesture is in progress.
11594e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     * @param supportDoubleTap Whether double-tap gestures are supported.
11604e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     */
11614e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    public void updateDoubleTapSupport(boolean supportDoubleTap) {
11621e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        assert !isDoubleTapActive();
11634e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        int doubleTapMode = supportDoubleTap ?
11644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                DOUBLE_TAP_MODE_NONE : DOUBLE_TAP_MODE_DISABLED;
11654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (mDoubleTapMode == doubleTapMode) return;
11664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        mDoubleTapMode = doubleTapMode;
11674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateDoubleTapListener();
11684e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
11694e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11704e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    /**
11710f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * Update whether double-tap gesture detection should be suppressed due to
11720f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * the viewport or scale of the current page. Suppressing double-tap gesture
11730f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * detection allows for rapid and responsive single-tap gestures.
11740f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)     * @param shouldDisableDoubleTap Whether double-tap should be suppressed.
11754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)     */
11760f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)    public void updateShouldDisableDoubleTap(boolean shouldDisableDoubleTap) {
11770f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        if (mShouldDisableDoubleTap == shouldDisableDoubleTap) return;
11780f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        mShouldDisableDoubleTap = shouldDisableDoubleTap;
11794e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        updateDoubleTapListener();
11803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
11813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
11824e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private boolean isDoubleTapDisabled() {
11830f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)        return mDoubleTapMode == DOUBLE_TAP_MODE_DISABLED || mShouldDisableDoubleTap;
11844e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
11854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11861e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    private boolean isDoubleTapActive() {
11871e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)        return mDoubleTapMode != DOUBLE_TAP_MODE_DISABLED &&
11881e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)               mDoubleTapMode != DOUBLE_TAP_MODE_NONE;
11891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    }
11901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
11914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    private void updateDoubleTapListener() {
11924e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        if (isDoubleTapDisabled()) {
11931e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            // Defer nulling the DoubleTapListener until the double tap gesture is complete.
11941e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)            if (isDoubleTapActive()) return;
11954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            mGestureDetector.setOnDoubleTapListener(null);
11964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        } else {
11974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            mGestureDetector.setOnDoubleTapListener(mDoubleTapListener);
11984e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        }
11994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
12003551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
1201f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1202f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private void reportDoubleTap() {
1203f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // Make sure repeated double taps don't get silently dropped from
1204f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        // the statistics.
1205f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mLastDoubleTapTimeMs > 0) {
1206f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mMotionEventDelegate.sendActionAfterDoubleTapUMA(
1207f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    ContentViewCore.UMAActionAfterDoubleTap.NO_ACTION, !mDisableClickDelay);
1208f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
1209f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1210f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        mLastDoubleTapTimeMs = SystemClock.uptimeMillis();
1211f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1212f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    /**
1214f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * Update the UMA stat tracking accidental double tap navigations with a user action.
1215f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     * @param type The action the user performed, one of the UMAActionAfterDoubleTap values
1216f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     *             defined in ContentViewCore.
1217f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)     */
1218f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    public void reportActionAfterDoubleTapUMA(int type) {
1219f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        updateDoubleTapUmaTimer();
1220f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1221f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mLastDoubleTapTimeMs == 0) return;
1222f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        long nowMs = SystemClock.uptimeMillis();
1224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if ((nowMs - mLastDoubleTapTimeMs) < ACTION_AFTER_DOUBLE_TAP_WINDOW_MS) {
1225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mMotionEventDelegate.sendActionAfterDoubleTapUMA(type, !mDisableClickDelay);
1226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mLastDoubleTapTimeMs = 0;
1227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
1228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
1229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1230f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // Watch for the UMA "action after double tap" timer expiring and reset
1231f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    // the timer if necessary.
1232f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    private void updateDoubleTapUmaTimer() {
1233f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if (mLastDoubleTapTimeMs == 0) return;
1234f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)
1235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        long nowMs = SystemClock.uptimeMillis();
1236f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        if ((nowMs - mLastDoubleTapTimeMs) >= ACTION_AFTER_DOUBLE_TAP_WINDOW_MS) {
1237f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            // Time expired, user took no action (that we care about).
1238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mMotionEventDelegate.sendActionAfterDoubleTapUMA(
1239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)                    ContentViewCore.UMAActionAfterDoubleTap.NO_ACTION, !mDisableClickDelay);
1240f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)            mLastDoubleTapTimeMs = 0;
1241f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        }
1242f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    }
12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1244