Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1120)

Unified Diff: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java

Issue 120513005: [Android] Perform eager gesture recognition on MotionEvents (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Allow scrolling after longpress Created 6 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
index be4e5f912ee2553c410dd10690b4449cace477c3..821f0c2b1c1068a48e1b285f4efe6eeafa489805 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java
@@ -22,6 +22,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.ResultReceiver;
+import android.os.SystemClock;
import android.provider.Browser;
import android.provider.Settings;
import android.text.Editable;
@@ -197,11 +198,6 @@ public class ContentViewCore
void onPinchGestureEnd();
/**
- * Called when the fling gesture is sent.
- */
- void onFlingStartGesture(int vx, int vy);
-
- /**
* Called when the fling cancel gesture is sent.
*/
void onFlingCancelGesture();
@@ -209,7 +205,7 @@ public class ContentViewCore
/**
* Called when a fling event was not handled by the renderer.
*/
- void onUnhandledFlingStartEvent();
+ void onUnhandledFlingStartEvent(int velocityX, int velocityY);
/**
* Called to indicate that a scroll update gesture had been consumed by the page.
@@ -372,7 +368,6 @@ public class ContentViewCore
private ContentViewGestureHandler mContentViewGestureHandler;
private GestureStateListener mGestureStateListener;
- private ZoomManager mZoomManager;
private ZoomControlsDelegate mZoomControlsDelegate;
private PopupZoomer mPopupZoomer;
@@ -460,12 +455,16 @@ public class ContentViewCore
// vsync.
private boolean mRequestedVSyncForInput = false;
+ // Used for tracking UMA ActionAfterDoubleTap to tell user's immediate
+ // action after a double tap.
+ private long mLastDoubleTapTimeMs;
+
private ViewAndroid mViewAndroid;
private SmartClipDataListener mSmartClipDataListener = null;
/** ActionAfterDoubleTap defined in tools/metrics/histograms/histograms.xml. */
- public static class UMAActionAfterDoubleTap {
+ private static class UMAActionAfterDoubleTap {
public static final int NAVIGATE_BACK = 0;
public static final int NAVIGATE_STOP = 1;
public static final int NO_ACTION = 2;
@@ -473,13 +472,19 @@ public class ContentViewCore
}
/** TapDelayType defined in tools/metrics/histograms/histograms.xml. */
- public static class UMASingleTapType {
+ private static class UMASingleTapType {
public static final int DELAYED_TAP = 0;
public static final int UNDELAYED_TAP = 1;
public static final int COUNT = 2;
}
/**
+ * Used by UMA stat for tracking accidental double tap navigations. Specifies the amount of
+ * time after a double tap within which actions will be recorded to the UMA stat.
+ */
+ private static final long ACTION_AFTER_DOUBLE_TAP_WINDOW_MS = 5000;
+
+ /**
* Constructs a new ContentViewCore. Embedders must call initialize() after constructing
* a ContentViewCore and before using it.
*
@@ -719,8 +724,7 @@ public class ContentViewCore
// Note ContentViewGestureHandler initialization must occur before nativeInit
// because nativeInit may callback into hasTouchEventHandlers.
- mZoomManager = new ZoomManager(mContext, this);
- mContentViewGestureHandler = new ContentViewGestureHandler(mContext, this, mZoomManager);
+ mContentViewGestureHandler = new ContentViewGestureHandler(mContext, this);
mZoomControlsDelegate = new ZoomControlsDelegate() {
@Override
public void invokeZoomPicker() {}
@@ -955,7 +959,7 @@ public class ContentViewCore
* Stops loading the current web contents.
*/
public void stopLoading() {
- reportActionAfterDoubleTapUMA(ContentViewCore.UMAActionAfterDoubleTap.NAVIGATE_STOP);
+ reportActionAfterDoubleTapUMA(UMAActionAfterDoubleTap.NAVIGATE_STOP);
if (mNativeContentViewCore != 0) nativeStopLoading(mNativeContentViewCore);
}
@@ -1271,37 +1275,26 @@ public class ContentViewCore
}
@Override
- public boolean sendTouchEvent(long timeMs, int action, TouchPoint[] pts) {
- if (mNativeContentViewCore != 0) {
- return nativeSendTouchEvent(mNativeContentViewCore, timeMs, action, pts);
- }
- return false;
- }
-
- @SuppressWarnings("unused")
- @CalledByNative
- private void hasTouchEventHandlers(boolean hasTouchHandlers) {
- mContentViewGestureHandler.hasTouchEventHandlers(hasTouchHandlers);
+ public void onTouchEventHandlingBegin(long timeMs, int action, TouchPoint[] pts) {
+ if (mNativeContentViewCore == 0) return;
+ nativeOnTouchEventHandlingBegin(mNativeContentViewCore, timeMs, action, pts);
}
- @SuppressWarnings("unused")
- @CalledByNative
- private void confirmTouchEvent(int ackResult) {
- mContentViewGestureHandler.confirmTouchEvent(ackResult);
+ @Override
+ public void onTouchEventHandlingEnd() {
+ if (mNativeContentViewCore == 0) return;
+ nativeOnTouchEventHandlingEnd(mNativeContentViewCore);
}
@SuppressWarnings("unused")
@CalledByNative
- private void onFlingStartEventAck(int ackResult) {
- if (ackResult == ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS
- && mGestureStateListener != null) {
- mGestureStateListener.onUnhandledFlingStartEvent();
- }
- if (ackResult != ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED) {
- // No fling happened for the fling start event.
- // Cancel the fling status set when sending GestureFlingStart.
- getContentViewClient().onFlingStopped();
+ private void onUnhandledFlingStartEventAck(boolean hadConsumer, float vx, float vy) {
+ if (mGestureStateListener != null && !hadConsumer) {
+ mGestureStateListener.onUnhandledFlingStartEvent((int) vx, (int) vy);
}
+ // No fling happened for the fling start event.
+ // Cancel the fling status set when sending GestureFlingStart.
+ getContentViewClient().onFlingStopped();
}
@SuppressWarnings("unused")
@@ -1324,19 +1317,29 @@ public class ContentViewCore
getContentViewClient().onScrollEndEvent();
}
- private void reportActionAfterDoubleTapUMA(int type) {
- mContentViewGestureHandler.reportActionAfterDoubleTapUMA(type);
+ @SuppressWarnings("unused")
+ @CalledByNative
+ private boolean onForwardingGestureEvent(int type, int x, int y) {
+ if (offerGestureToEmbedder(type)) return false;
+ updateTextHandlesForGesture(type);
+ updateGestureStateListener(type);
+ updateForTapOrPress(type, x, y);
+ updateForDoubleTapUMA(type);
+ // TODO(jdduke): Determine if this should be called while a pinch is active.
+ if (type == ContentViewGestureHandler.GESTURE_SCROLL_BY) {
+ mZoomControlsDelegate.invokeZoomPicker();
+ } else if (type == ContentViewGestureHandler.GESTURE_FLING_START) {
+ mContentViewClient.onFlingStarted();
+ }
+ return true;
}
@Override
public boolean sendGesture(int type, long timeMs, int x, int y, Bundle b) {
- if (offerGestureToEmbedder(type)) return false;
if (mNativeContentViewCore == 0) return false;
- updateTextHandlesForGesture(type);
- updateGestureStateListener(type, b);
switch (type) {
- case ContentViewGestureHandler.GESTURE_SHOW_PRESSED_STATE:
- nativeShowPressState(mNativeContentViewCore, timeMs, x, y);
+ case ContentViewGestureHandler.GESTURE_SHOW_PRESS:
+ nativeShowPress(mNativeContentViewCore, timeMs, x, y);
return true;
case ContentViewGestureHandler.GESTURE_TAP_CANCEL:
nativeTapCancel(mNativeContentViewCore, timeMs, x, y);
@@ -1351,17 +1354,19 @@ public class ContentViewCore
nativeSingleTap(mNativeContentViewCore, timeMs, x, y, false);
return true;
case ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED:
- handleTapOrPress(timeMs, x, y, 0,
- b.getBoolean(ContentViewGestureHandler.SHOW_PRESS, false));
+ if (!b.getBoolean(ContentViewGestureHandler.SHOW_PRESS, false)) {
+ nativeShowPress(mNativeContentViewCore, timeMs, x, y);
+ }
+ nativeSingleTap(mNativeContentViewCore, timeMs, x, y, false);
return true;
case ContentViewGestureHandler.GESTURE_SINGLE_TAP_UNCONFIRMED:
nativeSingleTapUnconfirmed(mNativeContentViewCore, timeMs, x, y);
return true;
case ContentViewGestureHandler.GESTURE_LONG_PRESS:
- handleTapOrPress(timeMs, x, y, IS_LONG_PRESS, false);
+ nativeLongPress(mNativeContentViewCore, timeMs, x, y, false);
return true;
case ContentViewGestureHandler.GESTURE_LONG_TAP:
- handleTapOrPress(timeMs, x, y, IS_LONG_TAP, false);
+ nativeLongTap(mNativeContentViewCore, timeMs, x, y, false);
return true;
case ContentViewGestureHandler.GESTURE_SCROLL_START: {
int dx = b.getInt(ContentViewGestureHandler.DELTA_HINT_X);
@@ -1379,7 +1384,6 @@ public class ContentViewCore
nativeScrollEnd(mNativeContentViewCore, timeMs);
return true;
case ContentViewGestureHandler.GESTURE_FLING_START:
- mContentViewClient.onFlingStarted();
nativeFlingStart(mNativeContentViewCore, timeMs, x, y,
b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0));
@@ -1407,31 +1411,11 @@ public class ContentViewCore
sendGesture(ContentViewGestureHandler.GESTURE_DOUBLE_TAP, timeMs, x, y, b);
}
- @Override
- public void sendSingleTapUMA(int type) {
- if (mNativeContentViewCore == 0) return;
- nativeSendSingleTapUma(
- mNativeContentViewCore,
- type,
- UMASingleTapType.COUNT);
- }
-
- @Override
- public void sendActionAfterDoubleTapUMA(int type,
- boolean clickDelayEnabled) {
- if (mNativeContentViewCore == 0) return;
- nativeSendActionAfterDoubleTapUma(
- mNativeContentViewCore,
- type,
- clickDelayEnabled,
- UMAActionAfterDoubleTap.COUNT);
- }
-
public void setGestureStateListener(GestureStateListener pinchGestureStateListener) {
mGestureStateListener = pinchGestureStateListener;
}
- void updateGestureStateListener(int gestureType, Bundle b) {
+ void updateGestureStateListener(int gestureType) {
if (mGestureStateListener == null) return;
switch (gestureType) {
@@ -1441,11 +1425,6 @@ public class ContentViewCore
case ContentViewGestureHandler.GESTURE_PINCH_END:
mGestureStateListener.onPinchGestureEnd();
break;
- case ContentViewGestureHandler.GESTURE_FLING_START:
- mGestureStateListener.onFlingStartGesture(
- b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
- b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0));
- break;
case ContentViewGestureHandler.GESTURE_FLING_CANCEL:
mGestureStateListener.onFlingCancelGesture();
break;
@@ -1976,8 +1955,11 @@ public class ContentViewCore
}
}
- private void handleTapOrPress(
- long timeMs, float xPix, float yPix, int isLongPressOrTap, boolean showPress) {
+ private void updateForTapOrPress(int type, float xPix, float yPix) {
+ if (type != ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED
+ && type != ContentViewGestureHandler.GESTURE_LONG_PRESS
+ && type != ContentViewGestureHandler.GESTURE_LONG_TAP) return;
+
if (mContainerView.isFocusable() && mContainerView.isFocusableInTouchMode()
&& !mContainerView.isFocused()) {
mContainerView.requestFocus();
@@ -1985,35 +1967,81 @@ public class ContentViewCore
if (!mPopupZoomer.isShowing()) mPopupZoomer.setLastTouch(xPix, yPix);
- if (isLongPressOrTap == IS_LONG_PRESS) {
- getInsertionHandleController().allowAutomaticShowing();
- getSelectionHandleController().allowAutomaticShowing();
- if (mNativeContentViewCore != 0) {
- nativeLongPress(mNativeContentViewCore, timeMs, xPix, yPix, false);
- }
- } else if (isLongPressOrTap == IS_LONG_TAP) {
+ if (type == ContentViewGestureHandler.GESTURE_LONG_PRESS
+ || type == ContentViewGestureHandler.GESTURE_LONG_TAP) {
getInsertionHandleController().allowAutomaticShowing();
getSelectionHandleController().allowAutomaticShowing();
- if (mNativeContentViewCore != 0) {
- nativeLongTap(mNativeContentViewCore, timeMs, xPix, yPix, false);
- }
} else {
- if (!showPress && mNativeContentViewCore != 0) {
- nativeShowPressState(mNativeContentViewCore, timeMs, xPix, yPix);
- }
if (mSelectionEditable) getInsertionHandleController().allowAutomaticShowing();
- if (mNativeContentViewCore != 0) {
- nativeSingleTap(mNativeContentViewCore, timeMs, xPix, yPix, false);
+ }
+ }
+
+ // Watch for the UMA "action after double tap" timer expiring and reset
+ // the timer if necessary.
+ private void updateDoubleTapUmaTimer() {
+ if (mLastDoubleTapTimeMs == 0) return;
+
+ long nowMs = SystemClock.uptimeMillis();
+ if ((nowMs - mLastDoubleTapTimeMs) >= ACTION_AFTER_DOUBLE_TAP_WINDOW_MS) {
+ // Time expired, user took no action (that we care about).
+ sendActionAfterDoubleTapUMA(UMAActionAfterDoubleTap.NO_ACTION);
+ mLastDoubleTapTimeMs = 0;
+ }
+ }
+
+ private void updateForDoubleTapUMA(int type) {
+ updateDoubleTapUmaTimer();
+
+ if (type == ContentViewGestureHandler.GESTURE_SINGLE_TAP_UP
+ || type == ContentViewGestureHandler.GESTURE_SINGLE_TAP_CONFIRMED) {
+ sendSingleTapUMA(mContentViewGestureHandler.isDoubleTapDisabled() ?
+ UMASingleTapType.UNDELAYED_TAP : UMASingleTapType.DELAYED_TAP);
+ } else if (type == ContentViewGestureHandler.GESTURE_DOUBLE_TAP) {
+ // Make sure repeated double taps don't get silently dropped from
+ // the statistics.
+ if (mLastDoubleTapTimeMs > 0) {
+ sendActionAfterDoubleTapUMA(UMAActionAfterDoubleTap.NO_ACTION);
}
+
+ mLastDoubleTapTimeMs = SystemClock.uptimeMillis();
+ }
+ }
+
+ private void reportActionAfterDoubleTapUMA(int type) {
+ updateDoubleTapUmaTimer();
+
+ if (mLastDoubleTapTimeMs == 0) return;
+
+ long nowMs = SystemClock.uptimeMillis();
+ if ((nowMs - mLastDoubleTapTimeMs) < ACTION_AFTER_DOUBLE_TAP_WINDOW_MS) {
+ sendActionAfterDoubleTapUMA(type);
+ mLastDoubleTapTimeMs = 0;
}
}
+ private void sendSingleTapUMA(int type) {
+ if (mNativeContentViewCore == 0) return;
+ nativeSendSingleTapUma(
+ mNativeContentViewCore,
+ type,
+ UMASingleTapType.COUNT);
+ }
+
+ private void sendActionAfterDoubleTapUMA(int type) {
+ if (mNativeContentViewCore == 0) return;
+ nativeSendActionAfterDoubleTapUma(
+ mNativeContentViewCore,
+ type,
+ !mContentViewGestureHandler.isClickDelayDisabled(),
+ UMAActionAfterDoubleTap.COUNT);
+ }
+
public void setZoomControlsDelegate(ZoomControlsDelegate zoomControlsDelegate) {
mZoomControlsDelegate = zoomControlsDelegate;
}
public void updateMultiTouchZoomSupport(boolean supportsMultiTouchZoom) {
- mZoomManager.updateMultiTouchSupport(supportsMultiTouchZoom);
+ mContentViewGestureHandler.updateMultiTouchSupport(supportsMultiTouchZoom);
}
public void updateDoubleTapSupport(boolean supportsDoubleTap) {
@@ -2732,17 +2760,15 @@ public class ContentViewCore
* @return whether the gesture was sent.
*/
public boolean pinchByDelta(float delta) {
- if (mNativeContentViewCore == 0) {
- return false;
- }
+ if (mNativeContentViewCore == 0) return false;
long timeMs = System.currentTimeMillis();
int xPix = getViewportWidthPix() / 2;
int yPix = getViewportHeightPix() / 2;
- getContentViewGestureHandler().pinchBegin(timeMs, xPix, yPix);
- getContentViewGestureHandler().pinchBy(timeMs, xPix, yPix, delta);
- getContentViewGestureHandler().pinchEnd(timeMs);
+ nativePinchBegin(mNativeContentViewCore, timeMs, xPix, yPix);
+ nativePinchBy(mNativeContentViewCore, timeMs, xPix, yPix, delta);
+ nativePinchEnd(mNativeContentViewCore, timeMs);
return true;
}
@@ -2750,7 +2776,6 @@ public class ContentViewCore
/**
* Invokes the graphical zoom picker widget for this ContentView.
*/
- @Override
public void invokeZoomPicker() {
mZoomControlsDelegate.invokeZoomPicker();
}
@@ -3250,9 +3275,11 @@ public class ContentViewCore
long nativeContentViewCoreImpl, int orientation);
// All touch events (including flings, scrolls etc) accept coordinates in physical pixels.
- private native boolean nativeSendTouchEvent(
+ private native void nativeOnTouchEventHandlingBegin(
long nativeContentViewCoreImpl, long timeMs, int action, TouchPoint[] pts);
+ private native void nativeOnTouchEventHandlingEnd(long nativeContentViewCoreImpl);
+
private native int nativeSendMouseMoveEvent(
long nativeContentViewCoreImpl, long timeMs, float x, float y);
@@ -3280,7 +3307,7 @@ public class ContentViewCore
private native void nativeSingleTapUnconfirmed(
long nativeContentViewCoreImpl, long timeMs, float x, float y);
- private native void nativeShowPressState(
+ private native void nativeShowPress(
long nativeContentViewCoreImpl, long timeMs, float x, float y);
private native void nativeTapCancel(

Powered by Google App Engine
This is Rietveld 408576698