diff options
author | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-02 19:11:46 +0000 |
---|---|---|
committer | mkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-08-02 19:11:46 +0000 |
commit | 75147f5e8bba70b224050852d23a22d26edcb57e (patch) | |
tree | b3a083f71c2d10c6d5de3b5d8e54845f5f4fa75f /android_webview/java | |
parent | 29afb163da5208e3c13ce2a9e1d739afd1e8da64 (diff) | |
download | chromium_src-75147f5e8bba70b224050852d23a22d26edcb57e.zip chromium_src-75147f5e8bba70b224050852d23a22d26edcb57e.tar.gz chromium_src-75147f5e8bba70b224050852d23a22d26edcb57e.tar.bz2 |
Handle root layer fling Java-side in android_webview.
The android_webview implementation needs to handle root layer fling
Java-side. This is required for proper integration with the android
view system which requires the fling scroll offset update to be
performed as a result of the computeScroll method.
BUG=None
TEST=AndroidWebViewTest
Review URL: https://chromiumcodereview.appspot.com/20990009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@215339 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview/java')
-rw-r--r-- | android_webview/java/src/org/chromium/android_webview/AwContents.java | 47 | ||||
-rw-r--r-- | android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java | 93 |
2 files changed, 130 insertions, 10 deletions
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java index 22be0d4..2d498da 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwContents.java +++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java @@ -31,6 +31,7 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.webkit.GeolocationPermissions; import android.webkit.ValueCallback; +import android.widget.OverScroller; import com.google.common.annotations.VisibleForTesting; @@ -372,10 +373,15 @@ public class AwContents { public int getContainerViewScrollY() { return mContainerView.getScrollY(); } + + @Override + public void invalidate() { + mContainerView.invalidate(); + } } //-------------------------------------------------------------------------------------------- - private class AwPinchGestureStateListener implements ContentViewCore.PinchGestureStateListener { + private class AwGestureStateListener implements ContentViewCore.GestureStateListener { @Override public void onPinchGestureStart() { // While it's possible to re-layout the view during a pinch gesture, the effect is very @@ -387,9 +393,26 @@ public class AwContents { mLayoutSizer.freezeLayoutRequests(); } + @Override public void onPinchGestureEnd() { mLayoutSizer.unfreezeLayoutRequests(); } + + @Override + public void onFlingStartGesture(int velocityX, int velocityY) { + mScrollOffsetManager.onFlingStartGesture(velocityX, velocityY); + } + + + @Override + public void onFlingCancelGesture() { + mScrollOffsetManager.onFlingCancelGesture(); + } + + @Override + public void onUnhandledFlingStartEvent() { + mScrollOffsetManager.onUnhandledFlingStartEvent(); + } } //-------------------------------------------------------------------------------------------- @@ -424,7 +447,7 @@ public class AwContents { private static ContentViewCore createAndInitializeContentViewCore(ViewGroup containerView, InternalAccessDelegate internalDispatcher, int nativeWebContents, - ContentViewCore.PinchGestureStateListener pinchGestureStateListener, + ContentViewCore.GestureStateListener pinchGestureStateListener, ContentViewClient contentViewClient, ContentViewCore.ZoomControlsDelegate zoomControlsDelegate) { ContentViewCore contentViewCore = new ContentViewCore(containerView.getContext()); @@ -432,7 +455,7 @@ public class AwContents { // compositor, not because input events are delivered immediately. contentViewCore.initialize(containerView, internalDispatcher, nativeWebContents, null, ContentViewCore.INPUT_EVENTS_DELIVERED_IMMEDIATELY); - contentViewCore.setPinchGestureStateListener(pinchGestureStateListener); + contentViewCore.setGestureStateListener(pinchGestureStateListener); contentViewCore.setContentViewClient(contentViewClient); contentViewCore.setZoomControlsDelegate(zoomControlsDelegate); return contentViewCore; @@ -479,7 +502,8 @@ public class AwContents { mSettings.setDefaultVideoPosterURL( mDefaultVideoPosterRequestHandler.getDefaultVideoPosterURL()); mContentsClient.setDIPScale(mDIPScale); - mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate()); + mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate(), + new OverScroller(mContainerView.getContext())); setOverScrollMode(mContainerView.getOverScrollMode()); @@ -513,7 +537,7 @@ public class AwContents { int nativeWebContents = nativeGetWebContents(mNativeAwContents); mContentViewCore = createAndInitializeContentViewCore( mContainerView, mInternalAccessAdapter, nativeWebContents, - new AwPinchGestureStateListener(), mContentsClient.getContentViewClient(), + new AwGestureStateListener(), mContentsClient.getContentViewClient(), mZoomControls); nativeSetJavaPeers(mNativeAwContents, this, mWebContentsDelegate, mContentsClientBridge, mIoThreadClient, mInterceptNavigationDelegate); @@ -870,6 +894,13 @@ public class AwContents { } /** + * @see View.computeScroll() + */ + public void computeScroll() { + mScrollOffsetManager.computeScrollAndAbsorbGlow(mOverScrollGlow); + } + + /** * @see View#computeHorizontalScrollRange() */ public int computeHorizontalScrollRange() { @@ -1174,8 +1205,8 @@ public class AwContents { /** * @see android.webkit.WebView#flingScroll(int, int) */ - public void flingScroll(int vx, int vy) { - mContentViewCore.flingScroll(vx, vy); + public void flingScroll(int velocityX, int velocityY) { + mContentViewCore.flingScroll(velocityX, velocityY); } /** @@ -1656,7 +1687,7 @@ public class AwContents { mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY); } - mScrollOffsetManager.overscrollBy(deltaX, deltaY); + mScrollOffsetManager.overScrollBy(deltaX, deltaY); if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) { mContainerView.invalidate(); diff --git a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java index 4564b42..86f693b 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java +++ b/android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java @@ -4,6 +4,10 @@ package org.chromium.android_webview; +import android.widget.OverScroller; + +import com.google.common.annotations.VisibleForTesting; + import org.chromium.base.CalledByNative; /** @@ -12,6 +16,7 @@ import org.chromium.base.CalledByNative; * * Unless otherwise values (sizes, scroll offsets) are in physical pixels. */ +@VisibleForTesting public class AwScrollOffsetManager { // The unit of all the values in this delegate are physical pixels. public interface Delegate { @@ -24,8 +29,11 @@ public class AwScrollOffsetManager { // operation, the native side shouldn't synchronously alter the scroll offset from within // this call. void scrollNativeTo(int x, int y); + int getContainerViewScrollX(); int getContainerViewScrollY(); + + void invalidate(); } private final Delegate mDelegate; @@ -42,14 +50,24 @@ public class AwScrollOffsetManager { private int mContainerViewWidth; private int mContainerViewHeight; + // Whether we're in the middle of processing a touch event. private boolean mProcessingTouchEvent; + // Whether (and to what value) to update the native side scroll offset after we've finished + // provessing a touch event. private boolean mApplyDeferredNativeScroll; private int mDeferredNativeScrollX; private int mDeferredNativeScrollY; - public AwScrollOffsetManager(Delegate delegate) { + // The velocity of the last recorded fling, + private int mLastFlingVelocityX; + private int mLastFlingVelocityY; + + private OverScroller mScroller; + + public AwScrollOffsetManager(Delegate delegate, OverScroller overScroller) { mDelegate = delegate; + mScroller = overScroller; } //----- Scroll range and extent calculation methods ------------------------------------------- @@ -133,12 +151,25 @@ public class AwScrollOffsetManager { } // Called by the native side to over-scroll the container view. - public void overscrollBy(int deltaX, int deltaY) { + public void overScrollBy(int deltaX, int deltaY) { + // TODO(mkosiba): Once http://crbug.com/260663 and http://crbug.com/261239 are fixed it + // should be possible to uncomment the following asserts: + // if (deltaX < 0) assert mDelegate.getContainerViewScrollX() == 0; + // if (deltaX > 0) assert mDelegate.getContainerViewScrollX() == + // computeMaximumHorizontalScrollOffset(); + scrollBy(deltaX, deltaY); + } + + private void scrollBy(int deltaX, int deltaY) { + if (deltaX == 0 && deltaY == 0) return; + final int scrollX = mDelegate.getContainerViewScrollX(); final int scrollY = mDelegate.getContainerViewScrollY(); final int scrollRangeX = computeMaximumHorizontalScrollOffset(); final int scrollRangeY = computeMaximumVerticalScrollOffset(); + // The android.view.View.overScrollBy method is used for both scrolling and over-scrolling + // which is why we use it here. mDelegate.overScrollContainerViewBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, mProcessingTouchEvent); } @@ -201,4 +232,62 @@ public class AwScrollOffsetManager { mDelegate.scrollNativeTo(x, y); } + + // Called at the beginning of every fling gesture. + public void onFlingStartGesture(int velocityX, int velocityY) { + mLastFlingVelocityX = velocityX; + mLastFlingVelocityY = velocityY; + } + + // Called whenever some other touch interaction requires the fling gesture to be canceled. + public void onFlingCancelGesture() { + // TODO(mkosiba): Support speeding up a fling by flinging again. + // http://crbug.com/265841 + mScroller.forceFinished(true); + } + + // Called when a fling gesture is not handled by the renderer. + // We explicitly ask the renderer not to handle fling gestures targeted at the root + // scroll layer. + public void onUnhandledFlingStartEvent() { + flingScroll(-mLastFlingVelocityX, -mLastFlingVelocityY); + } + + // Starts the fling animation. Called both as a response to a fling gesture and as via the + // public WebView#flingScroll(int, int) API. + public void flingScroll(int velocityX, int velocityY) { + final int scrollX = mDelegate.getContainerViewScrollX(); + final int scrollY = mDelegate.getContainerViewScrollY(); + final int rangeX = computeMaximumHorizontalScrollOffset(); + final int rangeY = computeMaximumVerticalScrollOffset(); + + mScroller.fling(scrollX, scrollY, velocityX, velocityY, + 0, rangeX, 0, rangeY); + mDelegate.invalidate(); + } + + // Called immediately before the draw to update the scroll offset. + public void computeScrollAndAbsorbGlow(OverScrollGlow overScrollGlow) { + final boolean stillAnimating = mScroller.computeScrollOffset(); + if (!stillAnimating) return; + + final int oldX = mDelegate.getContainerViewScrollX(); + final int oldY = mDelegate.getContainerViewScrollY(); + int x = mScroller.getCurrX(); + int y = mScroller.getCurrY(); + + int rangeX = computeMaximumHorizontalScrollOffset(); + int rangeY = computeMaximumVerticalScrollOffset(); + + if (overScrollGlow != null) { + overScrollGlow.absorbGlow(x, y, oldX, oldY, rangeX, rangeY, + mScroller.getCurrVelocity()); + } + + // The mScroller is configured not to go outside of the scrollable range, so this call + // should never result in attempting to scroll outside of the scrollable region. + scrollBy(x - oldX, y - oldY); + + mDelegate.invalidate(); + } } |