Expose more gestures to ContentViewCore.GestureStateListeners

* Let ContentViewCore manage more than one GestureStateListener.
* Change GestureStateListener to be an empty implementation.
* ContentViewCore alerts its GestureStateListeners of any scrolls
  or flings, and alerts it of changes in the vertical scroll offset
  or extent.  That last bit is admittedly a bit strange to put in
  the GestureStateListener, but it's going to be listening to starts
  and stops already anyway...

Downstream CL that uses it: https://chrome-internal-review.googlesource.com/#/c/152640/
BUG=332281

Review URL: https://codereview.chromium.org/145953005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@247825 0039d316-1c4b-4281-b951-d872f2087c98
parent b83aa83d
......@@ -48,6 +48,7 @@ import org.chromium.content.browser.LoadUrlParams;
import org.chromium.content.browser.NavigationHistory;
import org.chromium.content.browser.PageTransitionTypes;
import org.chromium.content.common.CleanupReference;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.gfx.DeviceDisplayInfo;
......@@ -382,7 +383,7 @@ public class AwContents {
}
//--------------------------------------------------------------------------------------------
private class AwGestureStateListener implements ContentViewCore.GestureStateListener {
private class AwGestureStateListener extends GestureStateListener {
@Override
public void onPinchGestureStart() {
// While it's possible to re-layout the view during a pinch gesture, the effect is very
......@@ -400,7 +401,8 @@ public class AwContents {
}
@Override
public void onFlingStartGesture(int velocityX, int velocityY) {
public void onFlingStartGesture(
int velocityX, int velocityY, int scrollOffsetY, int scrollExtentY) {
mScrollOffsetManager.onFlingStartGesture(velocityX, velocityY);
}
......@@ -517,7 +519,7 @@ public class AwContents {
private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
InternalAccessDelegate internalDispatcher, int nativeWebContents,
ContentViewCore.GestureStateListener pinchGestureStateListener,
GestureStateListener gestureStateListener,
ContentViewClient contentViewClient,
ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
Context context = containerView.getContext();
......@@ -526,7 +528,7 @@ public class AwContents {
context instanceof Activity ?
new ActivityWindowAndroid((Activity) context) :
new WindowAndroid(context.getApplicationContext()));
contentViewCore.setGestureStateListener(pinchGestureStateListener);
contentViewCore.addGestureStateListener(gestureStateListener);
contentViewCore.setContentViewClient(contentViewClient);
contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
return contentViewCore;
......
......@@ -13,8 +13,8 @@ import org.chromium.android_webview.test.util.AwTestTouchUtils;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.android_webview.test.util.JavascriptEventObserver;
import org.chromium.base.test.util.Feature;
import org.chromium.content.browser.ContentViewCore;
import org.chromium.content.browser.test.util.CallbackHelper;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.ui.gfx.DeviceDisplayInfo;
import java.util.concurrent.Callable;
......@@ -669,7 +669,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
}
}
private static class TestGestureStateListener implements ContentViewCore.GestureStateListener {
private static class TestGestureStateListener extends GestureStateListener {
private CallbackHelper mOnScrollUpdateGestureConsumedHelper = new CallbackHelper();
public CallbackHelper getOnScrollUpdateGestureConsumedHelper() {
......@@ -685,7 +685,8 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
}
@Override
public void onFlingStartGesture(int velocityX, int velocityY) {
public void onFlingStartGesture(
int velocityX, int velocityY, int scrollOffsetY, int scrollExtentY) {
}
@Override
......@@ -726,7 +727,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
testContainerView.getContentViewCore().setGestureStateListener(
testContainerView.getContentViewCore().addGestureStateListener(
testGestureStateListener);
}
});
......
......@@ -180,35 +180,4 @@ public class ContentViewClient {
return false;
}
/**
* Called when a fling start event is sent. Note: onFlingStopped() of the previous
* fling may be called after onFlingStarted() of the current fling, so if the
* client wants to manage the fling status, a counter should be used.
*/
public void onFlingStarted() {
}
/**
* Called when a fling is stopped, or a fling start event didn't trigger a fling.
*/
public void onFlingStopped() {
}
/**
* Called when a scroll gesture has begun.
*/
public void onScrollBeginEvent() {
}
/**
* Called when a scroll gesture has ended.
*/
public void onScrollEndEvent() {
}
/**
* Called when the scroll offsets or viewport dimensions may have changed.
*/
public void onScrollOrViewportChanged() {
}
}
......@@ -53,6 +53,8 @@ import com.google.common.annotations.VisibleForTesting;
import org.chromium.base.CalledByNative;
import org.chromium.base.CommandLine;
import org.chromium.base.JNINamespace;
import org.chromium.base.ObserverList;
import org.chromium.base.ObserverList.RewindableIterator;
import org.chromium.base.TraceEvent;
import org.chromium.base.WeakContext;
import org.chromium.content.R;
......@@ -69,6 +71,7 @@ import org.chromium.content.browser.input.SelectPopupDialog;
import org.chromium.content.browser.input.SelectPopupItem;
import org.chromium.content.browser.input.SelectionHandleController;
import org.chromium.content.common.ContentSwitches;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ViewAndroid;
import org.chromium.ui.base.ViewAndroidDelegate;
......@@ -181,45 +184,6 @@ public class ContentViewCore
boolean super_awakenScrollBars(int startDelay, boolean invalidate);
}
/**
* An interface that allows the embedder to be notified of events and state changes related to
* gesture processing.
*/
public interface GestureStateListener {
/**
* Called when the pinch gesture starts.
*/
void onPinchGestureStart();
/**
* Called when the pinch gesture ends.
*/
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();
/**
* Called when a fling event was not handled by the renderer.
*/
void onUnhandledFlingStartEvent();
/**
* Called to indicate that a scroll update gesture had been consumed by the page.
* This callback is called whenever any layer is scrolled (like a frame or div). It is
* not called when a JS touch handler consumes the event (preventDefault), it is not called
* for JS-initiated scrolling.
*/
void onScrollUpdateGestureConsumed();
}
/**
* An interface for controlling visibility and state of embedder-provided zoom controls.
*/
......@@ -371,7 +335,8 @@ public class ContentViewCore
private boolean mInForeground = false;
private ContentViewGestureHandler mContentViewGestureHandler;
private GestureStateListener mGestureStateListener;
private final ObserverList<GestureStateListener> mGestureStateListeners;
private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator;
private ZoomManager mZoomManager;
private ZoomControlsDelegate mZoomControlsDelegate;
......@@ -500,6 +465,8 @@ public class ContentViewCore
mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
mAccessibilityManager = (AccessibilityManager)
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mGestureStateListeners = new ObserverList<GestureStateListener>();
mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
}
/**
......@@ -869,6 +836,7 @@ public class ContentViewCore
mJavaScriptInterfaces.clear();
mRetainedJavaScriptObjects.clear();
unregisterAccessibilityContentObserver();
mGestureStateListeners.clear();
}
private void unregisterAccessibilityContentObserver() {
......@@ -1293,35 +1261,38 @@ public class ContentViewCore
@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_NO_CONSUMER_EXISTS) {
for (mGestureStateListenersIterator.rewind();
mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().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();
updateGestureStateListener(ContentViewGestureHandler.GESTURE_FLING_END, null);
}
}
@SuppressWarnings("unused")
@CalledByNative
private void onScrollBeginEventAck() {
getContentViewClient().onScrollBeginEvent();
updateGestureStateListener(ContentViewGestureHandler.GESTURE_SCROLL_START, null);
}
@SuppressWarnings("unused")
@CalledByNative
private void onScrollUpdateGestureConsumed() {
if (mGestureStateListener != null) {
mGestureStateListener.onScrollUpdateGestureConsumed();
for (mGestureStateListenersIterator.rewind();
mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed();
}
}
@SuppressWarnings("unused")
@CalledByNative
private void onScrollEndEventAck() {
getContentViewClient().onScrollEndEvent();
updateGestureStateListener(ContentViewGestureHandler.GESTURE_SCROLL_END, null);
}
private void reportActionAfterDoubleTapUMA(int type) {
......@@ -1379,7 +1350,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));
......@@ -1427,30 +1397,61 @@ public class ContentViewCore
UMAActionAfterDoubleTap.COUNT);
}
public void setGestureStateListener(GestureStateListener pinchGestureStateListener) {
mGestureStateListener = pinchGestureStateListener;
/**
* Add a listener that gets alerted on gesture state changes.
* @param listener Listener to add.
*/
public void addGestureStateListener(GestureStateListener listener) {
mGestureStateListeners.addObserver(listener);
}
void updateGestureStateListener(int gestureType, Bundle b) {
if (mGestureStateListener == null) return;
/**
* Removes a listener that was added to watch for gesture state changes.
* @param listener Listener to remove.
*/
public void removeGestureStateListener(GestureStateListener listener) {
mGestureStateListeners.removeObserver(listener);
}
switch (gestureType) {
case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
mGestureStateListener.onPinchGestureStart();
break;
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;
default:
break;
void updateGestureStateListener(int gestureType, Bundle b) {
for (mGestureStateListenersIterator.rewind();
mGestureStateListenersIterator.hasNext();) {
GestureStateListener listener = mGestureStateListenersIterator.next();
switch (gestureType) {
case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
listener.onPinchGestureStart();
break;
case ContentViewGestureHandler.GESTURE_PINCH_END:
listener.onPinchGestureEnd();
break;
case ContentViewGestureHandler.GESTURE_FLING_START:
listener.onFlingStartGesture(
b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0),
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
break;
case ContentViewGestureHandler.GESTURE_FLING_END:
listener.onFlingEndGesture(
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
break;
case ContentViewGestureHandler.GESTURE_FLING_CANCEL:
listener.onFlingCancelGesture();
break;
case ContentViewGestureHandler.GESTURE_SCROLL_START:
listener.onScrollStarted(
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
break;
case ContentViewGestureHandler.GESTURE_SCROLL_END:
listener.onScrollEnded(
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
break;
default:
break;
}
}
}
......@@ -2444,7 +2445,12 @@ public class ContentViewCore
onRenderCoordinatesUpdated();
if (scrollChanged || contentOffsetChanged) {
getContentViewClient().onScrollOrViewportChanged();
for (mGestureStateListenersIterator.rewind();
mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged(
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
}
}
if (needTemporarilyHideHandles) temporarilyHideTextHandles();
......@@ -3215,7 +3221,7 @@ public class ContentViewCore
@CalledByNative
private void onNativeFlingStopped() {
getContentViewClient().onFlingStopped();
updateGestureStateListener(ContentViewGestureHandler.GESTURE_FLING_END, null);
}
private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
......
......@@ -208,12 +208,13 @@ class ContentViewGestureHandler implements LongPressDelegate {
static final int GESTURE_SCROLL_END = 8;
static final int GESTURE_FLING_START = 9;
static final int GESTURE_FLING_CANCEL = 10;
static final int GESTURE_PINCH_BEGIN = 11;
static final int GESTURE_PINCH_BY = 12;
static final int GESTURE_PINCH_END = 13;
static final int GESTURE_TAP_CANCEL = 14;
static final int GESTURE_LONG_TAP = 15;
static final int GESTURE_TAP_DOWN = 16;
static final int GESTURE_FLING_END = 11;
static final int GESTURE_PINCH_BEGIN = 12;
static final int GESTURE_PINCH_BY = 13;
static final int GESTURE_PINCH_END = 14;
static final int GESTURE_TAP_CANCEL = 15;
static final int GESTURE_LONG_TAP = 16;
static final int GESTURE_TAP_DOWN = 17;
// These have to be kept in sync with content/port/common/input_event_ack_state.h
static final int INPUT_EVENT_ACK_STATE_UNKNOWN = 0;
......
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.content_public.browser;
/**
* A class that is notified of events and state changes related to gesture processing from
* the ContentViewCore.
*/
public class GestureStateListener {
/**
* Called when the pinch gesture starts.
*/
public void onPinchGestureStart() {}
/**
* Called when the pinch gesture ends.
*/
public void onPinchGestureEnd() {}
/**
* Called when the fling gesture is sent.
*/
public void onFlingStartGesture(int vx, int vy, int scrollOffsetY, int scrollExtentY) {}
/**
* Called when the fling cancel gesture is sent.
*/
public void onFlingCancelGesture() {}
/**
* Called when a fling has ended.
*/
public void onFlingEndGesture(int scrollOffsetY, int scrollExtentY) {}
/**
* Called when a fling event was not handled by the renderer.
*/
public void onUnhandledFlingStartEvent() {}
/**
* Called to indicate that a scroll update gesture had been consumed by the page.
* This callback is called whenever any layer is scrolled (like a frame or div). It is
* not called when a JS touch handler consumes the event (preventDefault), it is not called
* for JS-initiated scrolling.
*/
public void onScrollUpdateGestureConsumed() {}
/*
* Called when a scroll gesture has started.
*/
public void onScrollStarted(int scrollOffsetY, int scrollExtentY) {}
/*
* Called when a scroll gesture has stopped.
*/
public void onScrollEnded(int scrollOffsetY, int scrollExtentY) {}
/*
* Called when the scroll offsets or extents may have changed.
*/
public void onScrollOffsetOrExtentChanged(int scrollOffsetY, int scrollExtentY) {}
}
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment