summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authormkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-02 19:11:46 +0000
committermkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-02 19:11:46 +0000
commit75147f5e8bba70b224050852d23a22d26edcb57e (patch)
treeb3a083f71c2d10c6d5de3b5d8e54845f5f4fa75f /android_webview
parent29afb163da5208e3c13ce2a9e1d739afd1e8da64 (diff)
downloadchromium_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')
-rw-r--r--android_webview/browser/in_process_view_renderer.cc6
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java47
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java93
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java51
-rw-r--r--android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java5
5 files changed, 184 insertions, 18 deletions
diff --git a/android_webview/browser/in_process_view_renderer.cc b/android_webview/browser/in_process_view_renderer.cc
index d761124..73069cd 100644
--- a/android_webview/browser/in_process_view_renderer.cc
+++ b/android_webview/browser/in_process_view_renderer.cc
@@ -585,7 +585,11 @@ void InProcessViewRenderer::ScrollTo(gfx::Vector2d new_value) {
gfx::Vector2dF new_value_css = gfx::ToRoundedVector2d(
gfx::ScaleVector2d(new_value, 1.0f / (dip_scale_ * page_scale_factor_)));
- DCHECK(scroll_offset_css_ != new_value_css);
+ // It's possible that more than one set of unique physical coordinates maps
+ // to the same set of CSS coordinates which means we can't reliably early-out
+ // earlier in the call stack.
+ if (scroll_offset_css_ == new_value_css)
+ return;
scroll_offset_css_ = new_value_css;
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();
+ }
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
index 74891a4..c394774 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwScrollOffsetManagerTest.java
@@ -4,8 +4,10 @@
package org.chromium.android_webview.test;
+import android.content.Context;
import android.view.View;
import android.view.View.MeasureSpec;
+import android.widget.OverScroller;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -21,6 +23,7 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
private int mScrollY;
private int mNativeScrollX;
private int mNativeScrollY;
+ private int mInvalidateCount;
public int getOverScrollDeltaX() {
return mOverScrollDeltaX;
@@ -50,6 +53,10 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
return mNativeScrollY;
}
+ public int getInvalidateCount() {
+ return mInvalidateCount;
+ }
+
@Override
public void overScrollContainerViewBy(int deltaX, int deltaY, int scrollX, int scrollY,
int scrollRangeX, int scrollRangeY, boolean isTouchEvent) {
@@ -79,6 +86,11 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
public int getContainerViewScrollY() {
return mScrollY;
}
+
+ @Override
+ public void invalidate() {
+ mInvalidateCount += 1;
+ }
}
private void simulateScrolling(AwScrollOffsetManager offsetManager,
@@ -98,7 +110,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
@Feature({"AndroidWebView"})
public void testWhenContentSizeMatchesView() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int width = 132;
final int height = 212;
@@ -150,7 +163,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
@Feature({"AndroidWebView"})
public void testScrollRangeAndMaxOffset() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
@@ -207,7 +221,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
return overrideScrollY;
}
};
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
@@ -233,7 +248,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
return overrideScrollY;
}
};
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
offsetManager.setContentSize(CONTENT_WIDTH, CONTENT_HEIGHT);
offsetManager.setContainerViewSize(VIEW_WIDTH, VIEW_HEIGHT);
@@ -247,7 +263,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
@Feature({"AndroidWebView"})
public void testScrollContainerViewTo() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
@@ -269,7 +286,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
@Feature({"AndroidWebView"})
public void testOnContainerViewOverScrolled() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
@@ -293,7 +311,8 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
@Feature({"AndroidWebView"})
public void testDefersScrollUntilTouchEnd() {
TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
- AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate);
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
final int scrollX = 31;
final int scrollY = 41;
@@ -314,4 +333,22 @@ public class AwScrollOffsetManagerTest extends InstrumentationTestCase {
assertEquals(scrollX, delegate.getNativeScrollX());
assertEquals(scrollY, delegate.getNativeScrollY());
}
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testFlingScroll() {
+ TestScrollOffsetManagerDelegate delegate = new TestScrollOffsetManagerDelegate();
+ OverScroller scroller = new OverScroller(getInstrumentation().getContext());
+ AwScrollOffsetManager offsetManager = new AwScrollOffsetManager(delegate, scroller);
+
+ offsetManager.flingScroll(0, 101);
+ assertTrue(!scroller.isFinished());
+ assertTrue(delegate.getInvalidateCount() == 1);
+ assertEquals(101, (int) scroller.getCurrVelocity());
+
+ offsetManager.flingScroll(111, 0);
+ assertTrue(!scroller.isFinished());
+ assertTrue(delegate.getInvalidateCount() == 2);
+ assertEquals(111, (int) scroller.getCurrVelocity());
+ }
}
diff --git a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
index 3860484..b83690e 100644
--- a/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
+++ b/android_webview/test/shell/src/org/chromium/android_webview/test/AwTestContainerView.java
@@ -119,6 +119,11 @@ public class AwTestContainerView extends FrameLayout {
}
@Override
+ public void computeScroll() {
+ mAwContents.computeScroll();
+ }
+
+ @Override
public void onVisibilityChanged(View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
mAwContents.onVisibilityChanged(changedView, visibility);