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; ...@@ -48,6 +48,7 @@ import org.chromium.content.browser.LoadUrlParams;
import org.chromium.content.browser.NavigationHistory; import org.chromium.content.browser.NavigationHistory;
import org.chromium.content.browser.PageTransitionTypes; import org.chromium.content.browser.PageTransitionTypes;
import org.chromium.content.common.CleanupReference; import org.chromium.content.common.CleanupReference;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.ui.base.ActivityWindowAndroid; import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
import org.chromium.ui.gfx.DeviceDisplayInfo; import org.chromium.ui.gfx.DeviceDisplayInfo;
...@@ -382,7 +383,7 @@ public class AwContents { ...@@ -382,7 +383,7 @@ public class AwContents {
} }
//-------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------------------------
private class AwGestureStateListener implements ContentViewCore.GestureStateListener { private class AwGestureStateListener extends GestureStateListener {
@Override @Override
public void onPinchGestureStart() { public void onPinchGestureStart() {
// While it's possible to re-layout the view during a pinch gesture, the effect is very // While it's possible to re-layout the view during a pinch gesture, the effect is very
...@@ -400,7 +401,8 @@ public class AwContents { ...@@ -400,7 +401,8 @@ public class AwContents {
} }
@Override @Override
public void onFlingStartGesture(int velocityX, int velocityY) { public void onFlingStartGesture(
int velocityX, int velocityY, int scrollOffsetY, int scrollExtentY) {
mScrollOffsetManager.onFlingStartGesture(velocityX, velocityY); mScrollOffsetManager.onFlingStartGesture(velocityX, velocityY);
} }
...@@ -517,7 +519,7 @@ public class AwContents { ...@@ -517,7 +519,7 @@ public class AwContents {
private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView, private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView,
InternalAccessDelegate internalDispatcher, int nativeWebContents, InternalAccessDelegate internalDispatcher, int nativeWebContents,
ContentViewCore.GestureStateListener pinchGestureStateListener, GestureStateListener gestureStateListener,
ContentViewClient contentViewClient, ContentViewClient contentViewClient,
ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) { ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) {
Context context = containerView.getContext(); Context context = containerView.getContext();
...@@ -526,7 +528,7 @@ public class AwContents { ...@@ -526,7 +528,7 @@ public class AwContents {
context instanceof Activity ? context instanceof Activity ?
new ActivityWindowAndroid((Activity) context) : new ActivityWindowAndroid((Activity) context) :
new WindowAndroid(context.getApplicationContext())); new WindowAndroid(context.getApplicationContext()));
contentViewCore.setGestureStateListener(pinchGestureStateListener); contentViewCore.addGestureStateListener(gestureStateListener);
contentViewCore.setContentViewClient(contentViewClient); contentViewCore.setContentViewClient(contentViewClient);
contentViewCore.setZoomControlsDelegate(zoomControlsDelegate); contentViewCore.setZoomControlsDelegate(zoomControlsDelegate);
return contentViewCore; return contentViewCore;
......
...@@ -13,8 +13,8 @@ import org.chromium.android_webview.test.util.AwTestTouchUtils; ...@@ -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.CommonResources;
import org.chromium.android_webview.test.util.JavascriptEventObserver; import org.chromium.android_webview.test.util.JavascriptEventObserver;
import org.chromium.base.test.util.Feature; 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.browser.test.util.CallbackHelper;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.ui.gfx.DeviceDisplayInfo; import org.chromium.ui.gfx.DeviceDisplayInfo;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
...@@ -669,7 +669,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase { ...@@ -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(); private CallbackHelper mOnScrollUpdateGestureConsumedHelper = new CallbackHelper();
public CallbackHelper getOnScrollUpdateGestureConsumedHelper() { public CallbackHelper getOnScrollUpdateGestureConsumedHelper() {
...@@ -685,7 +685,8 @@ public class AndroidScrollIntegrationTest extends AwTestBase { ...@@ -685,7 +685,8 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
} }
@Override @Override
public void onFlingStartGesture(int velocityX, int velocityY) { public void onFlingStartGesture(
int velocityX, int velocityY, int scrollOffsetY, int scrollExtentY) {
} }
@Override @Override
...@@ -726,7 +727,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase { ...@@ -726,7 +727,7 @@ public class AndroidScrollIntegrationTest extends AwTestBase {
getInstrumentation().runOnMainSync(new Runnable() { getInstrumentation().runOnMainSync(new Runnable() {
@Override @Override
public void run() { public void run() {
testContainerView.getContentViewCore().setGestureStateListener( testContainerView.getContentViewCore().addGestureStateListener(
testGestureStateListener); testGestureStateListener);
} }
}); });
......
...@@ -180,35 +180,4 @@ public class ContentViewClient { ...@@ -180,35 +180,4 @@ public class ContentViewClient {
return false; 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; ...@@ -53,6 +53,8 @@ import com.google.common.annotations.VisibleForTesting;
import org.chromium.base.CalledByNative; import org.chromium.base.CalledByNative;
import org.chromium.base.CommandLine; import org.chromium.base.CommandLine;
import org.chromium.base.JNINamespace; 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.TraceEvent;
import org.chromium.base.WeakContext; import org.chromium.base.WeakContext;
import org.chromium.content.R; import org.chromium.content.R;
...@@ -69,6 +71,7 @@ import org.chromium.content.browser.input.SelectPopupDialog; ...@@ -69,6 +71,7 @@ import org.chromium.content.browser.input.SelectPopupDialog;
import org.chromium.content.browser.input.SelectPopupItem; import org.chromium.content.browser.input.SelectPopupItem;
import org.chromium.content.browser.input.SelectionHandleController; import org.chromium.content.browser.input.SelectionHandleController;
import org.chromium.content.common.ContentSwitches; import org.chromium.content.common.ContentSwitches;
import org.chromium.content_public.browser.GestureStateListener;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.ui.base.ViewAndroid; import org.chromium.ui.base.ViewAndroid;
import org.chromium.ui.base.ViewAndroidDelegate; import org.chromium.ui.base.ViewAndroidDelegate;
...@@ -181,45 +184,6 @@ public class ContentViewCore ...@@ -181,45 +184,6 @@ public class ContentViewCore
boolean super_awakenScrollBars(int startDelay, boolean invalidate); 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. * An interface for controlling visibility and state of embedder-provided zoom controls.
*/ */
...@@ -371,7 +335,8 @@ public class ContentViewCore ...@@ -371,7 +335,8 @@ public class ContentViewCore
private boolean mInForeground = false; private boolean mInForeground = false;
private ContentViewGestureHandler mContentViewGestureHandler; private ContentViewGestureHandler mContentViewGestureHandler;
private GestureStateListener mGestureStateListener; private final ObserverList<GestureStateListener> mGestureStateListeners;
private final RewindableIterator<GestureStateListener> mGestureStateListenersIterator;
private ZoomManager mZoomManager; private ZoomManager mZoomManager;
private ZoomControlsDelegate mZoomControlsDelegate; private ZoomControlsDelegate mZoomControlsDelegate;
...@@ -500,6 +465,8 @@ public class ContentViewCore ...@@ -500,6 +465,8 @@ public class ContentViewCore
mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint(); mInsertionHandlePoint = mRenderCoordinates.createNormalizedPoint();
mAccessibilityManager = (AccessibilityManager) mAccessibilityManager = (AccessibilityManager)
getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
mGestureStateListeners = new ObserverList<GestureStateListener>();
mGestureStateListenersIterator = mGestureStateListeners.rewindableIterator();
} }
/** /**
...@@ -869,6 +836,7 @@ public class ContentViewCore ...@@ -869,6 +836,7 @@ public class ContentViewCore
mJavaScriptInterfaces.clear(); mJavaScriptInterfaces.clear();
mRetainedJavaScriptObjects.clear(); mRetainedJavaScriptObjects.clear();
unregisterAccessibilityContentObserver(); unregisterAccessibilityContentObserver();
mGestureStateListeners.clear();
} }
private void unregisterAccessibilityContentObserver() { private void unregisterAccessibilityContentObserver() {
...@@ -1293,35 +1261,38 @@ public class ContentViewCore ...@@ -1293,35 +1261,38 @@ public class ContentViewCore
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void onFlingStartEventAck(int ackResult) { private void onFlingStartEventAck(int ackResult) {
if (ackResult == ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS if (ackResult == ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_NO_CONSUMER_EXISTS) {
&& mGestureStateListener != null) { for (mGestureStateListenersIterator.rewind();
mGestureStateListener.onUnhandledFlingStartEvent(); mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onUnhandledFlingStartEvent();
}
} }
if (ackResult != ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED) { if (ackResult != ContentViewGestureHandler.INPUT_EVENT_ACK_STATE_CONSUMED) {
// No fling happened for the fling start event. // No fling happened for the fling start event.
// Cancel the fling status set when sending GestureFlingStart. // Cancel the fling status set when sending GestureFlingStart.
getContentViewClient().onFlingStopped(); updateGestureStateListener(ContentViewGestureHandler.GESTURE_FLING_END, null);
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void onScrollBeginEventAck() { private void onScrollBeginEventAck() {
getContentViewClient().onScrollBeginEvent(); updateGestureStateListener(ContentViewGestureHandler.GESTURE_SCROLL_START, null);
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void onScrollUpdateGestureConsumed() { private void onScrollUpdateGestureConsumed() {
if (mGestureStateListener != null) { for (mGestureStateListenersIterator.rewind();
mGestureStateListener.onScrollUpdateGestureConsumed(); mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onScrollUpdateGestureConsumed();
} }
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")
@CalledByNative @CalledByNative
private void onScrollEndEventAck() { private void onScrollEndEventAck() {
getContentViewClient().onScrollEndEvent(); updateGestureStateListener(ContentViewGestureHandler.GESTURE_SCROLL_END, null);
} }
private void reportActionAfterDoubleTapUMA(int type) { private void reportActionAfterDoubleTapUMA(int type) {
...@@ -1379,7 +1350,6 @@ public class ContentViewCore ...@@ -1379,7 +1350,6 @@ public class ContentViewCore
nativeScrollEnd(mNativeContentViewCore, timeMs); nativeScrollEnd(mNativeContentViewCore, timeMs);
return true; return true;
case ContentViewGestureHandler.GESTURE_FLING_START: case ContentViewGestureHandler.GESTURE_FLING_START:
mContentViewClient.onFlingStarted();
nativeFlingStart(mNativeContentViewCore, timeMs, x, y, nativeFlingStart(mNativeContentViewCore, timeMs, x, y,
b.getInt(ContentViewGestureHandler.VELOCITY_X, 0), b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0)); b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0));
...@@ -1427,30 +1397,61 @@ public class ContentViewCore ...@@ -1427,30 +1397,61 @@ public class ContentViewCore
UMAActionAfterDoubleTap.COUNT); 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) { void updateGestureStateListener(int gestureType, Bundle b) {
case ContentViewGestureHandler.GESTURE_PINCH_BEGIN: for (mGestureStateListenersIterator.rewind();
mGestureStateListener.onPinchGestureStart(); mGestureStateListenersIterator.hasNext();) {
break; GestureStateListener listener = mGestureStateListenersIterator.next();
case ContentViewGestureHandler.GESTURE_PINCH_END: switch (gestureType) {
mGestureStateListener.onPinchGestureEnd(); case ContentViewGestureHandler.GESTURE_PINCH_BEGIN:
break; listener.onPinchGestureStart();
case ContentViewGestureHandler.GESTURE_FLING_START: break;
mGestureStateListener.onFlingStartGesture( case ContentViewGestureHandler.GESTURE_PINCH_END:
b.getInt(ContentViewGestureHandler.VELOCITY_X, 0), listener.onPinchGestureEnd();
b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0)); break;
break; case ContentViewGestureHandler.GESTURE_FLING_START:
case ContentViewGestureHandler.GESTURE_FLING_CANCEL: listener.onFlingStartGesture(
mGestureStateListener.onFlingCancelGesture(); b.getInt(ContentViewGestureHandler.VELOCITY_X, 0),
break; b.getInt(ContentViewGestureHandler.VELOCITY_Y, 0),
default: computeVerticalScrollOffset(),
break; 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 ...@@ -2444,7 +2445,12 @@ public class ContentViewCore
onRenderCoordinatesUpdated(); onRenderCoordinatesUpdated();
if (scrollChanged || contentOffsetChanged) { if (scrollChanged || contentOffsetChanged) {
getContentViewClient().onScrollOrViewportChanged(); for (mGestureStateListenersIterator.rewind();
mGestureStateListenersIterator.hasNext();) {
mGestureStateListenersIterator.next().onScrollOffsetOrExtentChanged(
computeVerticalScrollOffset(),
computeVerticalScrollExtent());
}
} }
if (needTemporarilyHideHandles) temporarilyHideTextHandles(); if (needTemporarilyHideHandles) temporarilyHideTextHandles();
...@@ -3215,7 +3221,7 @@ public class ContentViewCore ...@@ -3215,7 +3221,7 @@ public class ContentViewCore
@CalledByNative @CalledByNative
private void onNativeFlingStopped() { private void onNativeFlingStopped() {
getContentViewClient().onFlingStopped(); updateGestureStateListener(ContentViewGestureHandler.GESTURE_FLING_END, null);
} }
private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl); private native WebContents nativeGetWebContentsAndroid(long nativeContentViewCoreImpl);
......
...@@ -208,12 +208,13 @@ class ContentViewGestureHandler implements LongPressDelegate { ...@@ -208,12 +208,13 @@ class ContentViewGestureHandler implements LongPressDelegate {
static final int GESTURE_SCROLL_END = 8; static final int GESTURE_SCROLL_END = 8;
static final int GESTURE_FLING_START = 9; static final int GESTURE_FLING_START = 9;
static final int GESTURE_FLING_CANCEL = 10; static final int GESTURE_FLING_CANCEL = 10;
static final int GESTURE_PINCH_BEGIN = 11; static final int GESTURE_FLING_END = 11;
static final int GESTURE_PINCH_BY = 12; static final int GESTURE_PINCH_BEGIN = 12;
static final int GESTURE_PINCH_END = 13; static final int GESTURE_PINCH_BY = 13;
static final int GESTURE_TAP_CANCEL = 14; static final int GESTURE_PINCH_END = 14;
static final int GESTURE_LONG_TAP = 15; static final int GESTURE_TAP_CANCEL = 15;
static final int GESTURE_TAP_DOWN = 16; 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 // 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; 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