Index: android_webview/java/src/org/chromium/android_webview/AwScrollOffsetManager.java |
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 4564b42ff04c4f76e2bf45c42611cd21bae64bb0..86f693b3fc198f38b75026c65b7e9ff6da8ff23d 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(); |
+ } |
} |