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