summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrbyers@chromium.org <rbyers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-30 20:09:31 +0000
committerrbyers@chromium.org <rbyers@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-12-30 20:09:31 +0000
commit75daf28ce6bad611eacdc1503934dbd092708f2a (patch)
tree700b98e12e1af94e247a0f38ac7a62801e1a76af
parent1160f9968fe8ab12b5543f475e110a08e386b568 (diff)
downloadchromium_src-75daf28ce6bad611eacdc1503934dbd092708f2a.zip
chromium_src-75daf28ce6bad611eacdc1503934dbd092708f2a.tar.gz
chromium_src-75daf28ce6bad611eacdc1503934dbd092708f2a.tar.bz2
Implement scroll begin hints on Android for touch-action
ScrollBegin gesture events can now take a "deltaXhint" and "deltaYhint" that provide some information about the motion that triggered the start of a scroll. This is used, for example, for touch-action: pan-x/pan-y support which needs to know what direction the user is scrolling as soon as the scroll starts. Aura already populates these fields, and this CL adds Android support as well. Also stop suppressing the sending of touch events to native code during a scroll. This is a hold-over from when touchcancel logic was implemented in Java. BUG=321643 R=jdduke@chromium.org Review URL: https://codereview.chromium.org/121913002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@242730 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--content/browser/android/content_view_core_impl.cc12
-rw-r--r--content/browser/android/content_view_core_impl.h3
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewCore.java13
-rw-r--r--content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java46
-rw-r--r--content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java83
5 files changed, 140 insertions, 17 deletions
diff --git a/content/browser/android/content_view_core_impl.cc b/content/browser/android/content_view_core_impl.cc
index b111f0b..5b9ab48 100644
--- a/content/browser/android/content_view_core_impl.cc
+++ b/content/browser/android/content_view_core_impl.cc
@@ -985,10 +985,18 @@ void ContentViewCoreImpl::SendGestureEvent(
rwhv->SendGestureEvent(event);
}
-void ContentViewCoreImpl::ScrollBegin(JNIEnv* env, jobject obj, jlong time_ms,
- jfloat x, jfloat y) {
+void ContentViewCoreImpl::ScrollBegin(JNIEnv* env,
+ jobject obj,
+ jlong time_ms,
+ jfloat x,
+ jfloat y,
+ jfloat hintx,
+ jfloat hinty) {
WebGestureEvent event = MakeGestureEvent(
WebInputEvent::GestureScrollBegin, time_ms, x, y);
+ event.data.scrollBegin.deltaXHint = hintx / GetDpiScale();
+ event.data.scrollBegin.deltaYHint = hinty / GetDpiScale();
+
SendGestureEvent(event);
}
diff --git a/content/browser/android/content_view_core_impl.h b/content/browser/android/content_view_core_impl.h
index 7b86bc9..0ef9070 100644
--- a/content/browser/android/content_view_core_impl.h
+++ b/content/browser/android/content_view_core_impl.h
@@ -111,7 +111,8 @@ class ContentViewCoreImpl : public ContentViewCore,
jfloat x,
jfloat y,
jfloat vertical_axis);
- void ScrollBegin(JNIEnv* env, jobject obj, jlong time_ms, jfloat x, jfloat y);
+ void ScrollBegin(JNIEnv* env, jobject obj, jlong time_ms,
+ jfloat x, jfloat y, jfloat hintx, jfloat hinty);
void ScrollEnd(JNIEnv* env, jobject obj, jlong time_ms);
void ScrollBy(JNIEnv* env, jobject obj, jlong time_ms,
jfloat x, jfloat y, jfloat dx, jfloat dy);
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 f3c123f..243de63 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
@@ -1408,9 +1408,12 @@ public class ContentViewCore
case ContentViewGestureHandler.GESTURE_LONG_TAP:
handleTapOrPress(timeMs, x, y, IS_LONG_TAP, false);
return true;
- case ContentViewGestureHandler.GESTURE_SCROLL_START:
- nativeScrollBegin(mNativeContentViewCore, timeMs, x, y);
+ case ContentViewGestureHandler.GESTURE_SCROLL_START: {
+ int dx = b.getInt(ContentViewGestureHandler.DELTA_HINT_X);
+ int dy = b.getInt(ContentViewGestureHandler.DELTA_HINT_Y);
+ nativeScrollBegin(mNativeContentViewCore, timeMs, x, y, dx, dy);
return true;
+ }
case ContentViewGestureHandler.GESTURE_SCROLL_BY: {
int dx = b.getInt(ContentViewGestureHandler.DISTANCE_X);
int dy = b.getInt(ContentViewGestureHandler.DISTANCE_Y);
@@ -1932,7 +1935,8 @@ public class ContentViewCore
final float dyPix = yPix - yCurrentPix;
if (dxPix != 0 || dyPix != 0) {
long time = System.currentTimeMillis();
- nativeScrollBegin(mNativeContentViewCore, time, xCurrentPix, yCurrentPix);
+ nativeScrollBegin(mNativeContentViewCore, time,
+ xCurrentPix, yCurrentPix, -dxPix, -dyPix);
nativeScrollBy(mNativeContentViewCore,
time, xCurrentPix, yCurrentPix, dxPix, dyPix);
nativeScrollEnd(mNativeContentViewCore, time);
@@ -3291,7 +3295,8 @@ public class ContentViewCore
long nativeContentViewCoreImpl, long timeMs, float x, float y, float verticalAxis);
private native void nativeScrollBegin(
- long nativeContentViewCoreImpl, long timeMs, float x, float y);
+ long nativeContentViewCoreImpl, long timeMs, float x, float y, float hintX,
+ float hintY);
private native void nativeScrollEnd(long nativeContentViewCoreImpl, long timeMs);
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
index b4b8524..cc5d2d2 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewGestureHandler.java
@@ -39,14 +39,22 @@ class ContentViewGestureHandler implements LongPressDelegate {
*/
static final String VELOCITY_Y = "Velocity Y";
/**
- * Used for GESTURE_SCROLL_BY x distance
+ * Used for GESTURE_SCROLL_BY x distance (scroll offset of update)
*/
static final String DISTANCE_X = "Distance X";
/**
- * Used for GESTURE_SCROLL_BY y distance
+ * Used for GESTURE_SCROLL_BY y distance (scroll offset of update)
*/
static final String DISTANCE_Y = "Distance Y";
/**
+ * Used for GESTURE_SCROLL_START delta X hint (movement triggering scroll)
+ */
+ static final String DELTA_HINT_X = "Delta Hint X";
+ /**
+ * Used for GESTURE_SCROLL_START delta Y hint (movement triggering scroll)
+ */
+ static final String DELTA_HINT_Y = "Delta Hint Y";
+ /**
* Used in GESTURE_SINGLE_TAP_CONFIRMED to check whether ShowPress has been called before.
*/
static final String SHOW_PRESS = "ShowPress";
@@ -64,6 +72,7 @@ class ContentViewGestureHandler implements LongPressDelegate {
private final Bundle mExtraParamBundleSingleTap;
private final Bundle mExtraParamBundleFling;
private final Bundle mExtraParamBundleScroll;
+ private final Bundle mExtraParamBundleScrollStart;
private final Bundle mExtraParamBundleDoubleTapDragZoom;
private final Bundle mExtraParamBundlePinchBy;
private GestureDetector mGestureDetector;
@@ -268,6 +277,7 @@ class ContentViewGestureHandler implements LongPressDelegate {
mExtraParamBundleSingleTap = new Bundle();
mExtraParamBundleFling = new Bundle();
mExtraParamBundleScroll = new Bundle();
+ mExtraParamBundleScrollStart = new Bundle();
mExtraParamBundleDoubleTapDragZoom = new Bundle();
mExtraParamBundlePinchBy = new Bundle();
@@ -326,8 +336,10 @@ class ContentViewGestureHandler implements LongPressDelegate {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
+ float rawDistanceX, float rawDistanceY) {
assert e1.getEventTime() <= e2.getEventTime();
+ float distanceX = rawDistanceX;
+ float distanceY = rawDistanceY;
if (!mSeenFirstScrollEvent) {
// Remove the touch slop region from the first scroll event to avoid a
// jump.
@@ -355,11 +367,18 @@ class ContentViewGestureHandler implements LongPressDelegate {
if (!mTouchScrolling) {
sendTapCancelIfNecessary(e1);
endFlingIfNecessary(e2.getEventTime());
+ // Note that scroll start hints are in distance traveled, where
+ // scroll deltas are in the opposite direction.
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_X, (int) -rawDistanceX);
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_Y, (int) -rawDistanceY);
+ assert mExtraParamBundleScrollStart.size() == 2;
if (sendGesture(GESTURE_SCROLL_START, e2.getEventTime(),
- (int) e1.getX(), (int) e1.getY(), null)) {
+ (int) e1.getX(), (int) e1.getY(),
+ mExtraParamBundleScrollStart)) {
mTouchScrolling = true;
}
}
+
// distanceX and distanceY is the scrolling offset since last onScroll.
// Because we are passing integers to webkit, this could introduce
// rounding errors. The rounding errors will accumulate overtime.
@@ -497,8 +516,14 @@ class ContentViewGestureHandler implements LongPressDelegate {
if (distanceX * distanceX + distanceY * distanceY >
mScaledTouchSlopSquare) {
sendTapCancelIfNecessary(e);
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_X,
+ (int) -distanceX);
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_Y,
+ (int) -distanceY);
+ assert mExtraParamBundleScrollStart.size() == 2;
sendGesture(GESTURE_SCROLL_START, e.getEventTime(),
- (int) e.getX(), (int) e.getY(), null);
+ (int) e.getX(), (int) e.getY(),
+ mExtraParamBundleScrollStart);
pinchBegin(e.getEventTime(),
Math.round(mDoubleTapDragZoomAnchorX),
Math.round(mDoubleTapDragZoomAnchorY));
@@ -616,7 +641,11 @@ class ContentViewGestureHandler implements LongPressDelegate {
if (!mTouchScrolling) {
// The native side needs a GESTURE_SCROLL_BEGIN before GESTURE_FLING_START
// to send the fling to the correct target. Send if it has not sent.
- sendGesture(GESTURE_SCROLL_START, timeMs, x, y, null);
+ // The distance traveled in one second is a reasonable scroll start hint.
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_X, velocityX);
+ mExtraParamBundleScrollStart.putInt(DELTA_HINT_Y, velocityY);
+ assert mExtraParamBundleScrollStart.size() == 2;
+ sendGesture(GESTURE_SCROLL_START, timeMs, x, y, mExtraParamBundleScrollStart);
}
endTouchScrollIfNecessary(timeMs, false);
@@ -917,7 +946,10 @@ class ContentViewGestureHandler implements LongPressDelegate {
}
}
- if (mTouchScrolling || mPinchInProgress) return EVENT_NOT_FORWARDED;
+ // TODO(rbyers): Remove this - content should be the one to decide when
+ // to drop touch events (eg. for touch-action). Need to test / fix
+ // touch-action scenarios with pinch - http://crbug.com/247566
+ if (mPinchInProgress) return EVENT_NOT_FORWARDED;
TouchPoint[] pts = new TouchPoint[event.getPointerCount()];
int type = TouchPoint.createTouchPoints(event, pts);
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
index 6354c8f..2718271 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewGestureHandlerTest.java
@@ -650,8 +650,17 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
assertEquals("scrollBegin should be sent before scrollBy",
ContentViewGestureHandler.GESTURE_SCROLL_START,
(int) mockDelegate.mGestureTypeList.get(2));
+ GestureRecordingMotionEventDelegate.GestureEvent startEvent =
+ mockDelegate.getActiveScrollStartEvent();
+ assertNotNull(startEvent);
assertEquals("scrollBegin should have the time of the ACTION_MOVE",
- eventTime + 10, (long) mockDelegate.mGestureTimeList.get(2));
+ eventTime + 10, (long) startEvent.getTimeMs());
+ int hintX = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_X);
+ int hintY = startEvent.getExtraParams().getInt(ContentViewGestureHandler.DELTA_HINT_Y);
+ // We don't want to take a dependency here on exactly how hints are calculated for a
+ // fling (eg. may depend on velocity), so just validate the direction.
+ assertTrue("scrollBegin hint should be in positive X axis",
+ hintX > 0 && hintY > 0 && hintX > hintY);
event = MotionEvent.obtain(
downTime, eventTime + 15, MotionEvent.ACTION_UP,
@@ -979,6 +988,17 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
assertTrue("GESTURE_SCROLL_START should have been sent",
mockDelegate.mGestureTypeList.contains(
ContentViewGestureHandler.GESTURE_SCROLL_START));
+ GestureRecordingMotionEventDelegate.GestureEvent startEvent =
+ mockDelegate.getActiveScrollStartEvent();
+ assertEquals(FAKE_COORD_X, startEvent.getX());
+ assertEquals(FAKE_COORD_Y + 100, startEvent.getY());
+ Bundle extraParams = startEvent.getExtraParams();
+ assertNotNull(extraParams);
+ assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
+ 0, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
+ assertEquals("GESTURE_SCROLL_START should have an X hint equal to the distance traveled",
+ 100, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
+
assertEquals("GESTURE_PINCH_BEGIN should have been sent",
ContentViewGestureHandler.GESTURE_PINCH_BEGIN,
mockDelegate.mMostRecentGestureEvent.mType);
@@ -1107,7 +1127,8 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
}
/**
- * Mock MotionEventDelegate that remembers the most recent gesture event.
+ * Mock MotionEventDelegate that remembers the most recent gesture event and any
+ * currently active scroll start event.
*/
static class GestureRecordingMotionEventDelegate implements MotionEventDelegate {
static class GestureEvent {
@@ -1146,6 +1167,7 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
}
}
private GestureEvent mMostRecentGestureEvent;
+ private GestureEvent mActiveScrollStartEvent;
private final ArrayList<Integer> mGestureTypeList = new ArrayList<Integer>();
private final ArrayList<Long> mGestureTimeList = new ArrayList<Long>();
@@ -1160,6 +1182,11 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
mMostRecentGestureEvent = new GestureEvent(type, timeMs, x, y, extraParams);
mGestureTypeList.add(mMostRecentGestureEvent.mType);
mGestureTimeList.add(timeMs);
+ if (type == ContentViewGestureHandler.GESTURE_SCROLL_START)
+ mActiveScrollStartEvent = mMostRecentGestureEvent;
+ else if (type == ContentViewGestureHandler.GESTURE_SCROLL_END ||
+ type == ContentViewGestureHandler.GESTURE_FLING_CANCEL)
+ mActiveScrollStartEvent = null;
return true;
}
@@ -1182,6 +1209,10 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
public GestureEvent getMostRecentGestureEvent() {
return mMostRecentGestureEvent;
}
+
+ public GestureEvent getActiveScrollStartEvent() {
+ return mActiveScrollStartEvent;
+ }
}
/**
@@ -1201,7 +1232,8 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
assertTrue(gestureHandler.onTouchEvent(event));
- // Move twice, because the first move gesture is discarded.
+ // Move twice so that we get two GESTURE_SCROLL_BY events and can compare
+ // the relative and absolute coordinates.
event = MotionEvent.obtain(
downTime, downTime + 5, MotionEvent.ACTION_MOVE,
FAKE_COORD_X - deltaX / 2, FAKE_COORD_Y - deltaY / 2, 0);
@@ -1229,6 +1261,51 @@ public class ContentViewGestureHandlerTest extends InstrumentationTestCase {
}
/**
+ * Generate a scroll gesture and verify that the resulting scroll start event
+ * has the expected hint values.
+ */
+ @SmallTest
+ @Feature({"Gestures"})
+ public void testScrollStartValues() {
+ final int deltaX = 13;
+ final int deltaY = 89;
+ final long downTime = SystemClock.uptimeMillis();
+
+ GestureRecordingMotionEventDelegate delegate = new GestureRecordingMotionEventDelegate();
+ ContentViewGestureHandler gestureHandler = new ContentViewGestureHandler(
+ getInstrumentation().getTargetContext(), delegate, mMockZoomManager);
+ MotionEvent event = motionEvent(MotionEvent.ACTION_DOWN, downTime, downTime);
+ assertTrue(gestureHandler.onTouchEvent(event));
+
+ // Move twice such that the first event isn't sufficient to start
+ // scrolling on it's own.
+ event = MotionEvent.obtain(
+ downTime, downTime + 5, MotionEvent.ACTION_MOVE,
+ FAKE_COORD_X + 2, FAKE_COORD_Y + 1, 0);
+ assertFalse(gestureHandler.onTouchEvent(event));
+ assertNull("Expect scrolling hasn't yet started",
+ delegate.getActiveScrollStartEvent());
+
+ event = MotionEvent.obtain(
+ downTime, downTime + 10, MotionEvent.ACTION_MOVE,
+ FAKE_COORD_X + deltaX, FAKE_COORD_Y + deltaY, 0);
+ assertTrue(gestureHandler.onTouchEvent(event));
+
+ GestureRecordingMotionEventDelegate.GestureEvent startEvent =
+ delegate.getActiveScrollStartEvent();
+ assertNotNull(startEvent);
+ assertEquals(ContentViewGestureHandler.GESTURE_SCROLL_START, startEvent.getType());
+ assertEquals(downTime + 10, startEvent.getTimeMs());
+ assertEquals(FAKE_COORD_X, startEvent.getX());
+ assertEquals(FAKE_COORD_Y, startEvent.getY());
+
+ Bundle extraParams = startEvent.getExtraParams();
+ assertNotNull(extraParams);
+ assertEquals(deltaX, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_X));
+ assertEquals(deltaY, extraParams.getInt(ContentViewGestureHandler.DELTA_HINT_Y));
+ }
+
+ /**
* Verify that the timer of LONG_PRESS will be cancelled when scrolling begins so
* LONG_PRESS and LONG_TAP won't be triggered.
*