summaryrefslogtreecommitdiffstats
path: root/android_webview/java
diff options
context:
space:
mode:
authormkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-24 17:26:38 +0000
committermkosiba@chromium.org <mkosiba@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-07-24 17:26:38 +0000
commit5719f8f6aff4369c125df3e0f728fd1cd3efa254 (patch)
tree6f8e30c52852cbdeeab7c2d4ad62655b4c773534 /android_webview/java
parent71a86c28cc057c8d8afab97d0f2d6dad74127329 (diff)
downloadchromium_src-5719f8f6aff4369c125df3e0f728fd1cd3efa254.zip
chromium_src-5719f8f6aff4369c125df3e0f728fd1cd3efa254.tar.gz
chromium_src-5719f8f6aff4369c125df3e0f728fd1cd3efa254.tar.bz2
[android_webview] Implement setOverScrollMode.
This implements AwContents.setOverScrollMode and adds the OverScrollGlow class that takes care of drawing the overscroll glow. BUG=b/6946454 TEST=manual: launch test shell, overscroll a page Java-only change. Ran through trybots. NOTRY=true Review URL: https://chromiumcodereview.appspot.com/19619002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@213456 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview/java')
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java79
-rw-r--r--android_webview/java/src/org/chromium/android_webview/OverScrollGlow.java210
2 files changed, 270 insertions, 19 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 c94c1ab..00dc0ab 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -143,8 +143,9 @@ public class AwContents {
private final InterceptNavigationDelegateImpl mInterceptNavigationDelegate;
private final InternalAccessDelegate mInternalAccessAdapter;
private final AwLayoutSizer mLayoutSizer;
- private final AwScrollOffsetManager mScrollOffsetManager;
private final AwZoomControls mZoomControls;
+ private final AwScrollOffsetManager mScrollOffsetManager;
+ private OverScrollGlow mOverScrollGlow;
// This can be accessed on any thread after construction. See AwContentsIoThreadClient.
private final AwSettings mSettings;
@@ -481,6 +482,8 @@ public class AwContents {
mContentsClient.setDIPScale(mDIPScale);
mScrollOffsetManager = new AwScrollOffsetManager(new AwScrollOffsetManagerDelegate());
+ setOverScrollMode(mContainerView.getOverScrollMode());
+
setNewAwContents(nativeInit(browserContext));
}
@@ -659,6 +662,12 @@ public class AwContents {
Log.w(TAG, "nativeOnDraw failed; clearing to background color.");
canvas.drawColor(getEffectiveBackgroundColor());
}
+
+ if (mOverScrollGlow != null && mOverScrollGlow.drawEdgeGlows(canvas,
+ mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
+ mScrollOffsetManager.computeMaximumVerticalScrollOffset())) {
+ mContainerView.invalidate();
+ }
}
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
@@ -673,23 +682,6 @@ public class AwContents {
return (int) Math.ceil(mContentViewCore.getContentWidthCss());
}
- /**
- * Called by the embedder when the scroll offset of the containing view has changed.
- * @see View#onScrollChanged(int,int)
- */
- public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) {
- mScrollOffsetManager.onContainerViewScrollChanged(l, t);
- }
-
- /**
- * Called by the embedder when the containing view is to be scrolled or overscrolled.
- * @see View#onOverScrolled(int,int,int,int)
- */
- public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
- boolean clampedY) {
- mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
- }
-
public Picture capturePicture() {
return nativeCapturePicture(mNativeAwContents);
}
@@ -854,6 +846,44 @@ public class AwContents {
}
/**
+ * @see View#setOverScrollMode(int)
+ */
+ public void setOverScrollMode(int mode) {
+ if (mode != View.OVER_SCROLL_NEVER) {
+ mOverScrollGlow = new OverScrollGlow(mContainerView);
+ } else {
+ mOverScrollGlow = null;
+ }
+ }
+
+ /**
+ * Called by the embedder when the scroll offset of the containing view has changed.
+ * @see View#onScrollChanged(int,int)
+ */
+ public void onContainerViewScrollChanged(int l, int t, int oldl, int oldt) {
+ mScrollOffsetManager.onContainerViewScrollChanged(l, t);
+ }
+
+ /**
+ * Called by the embedder when the containing view is to be scrolled or overscrolled.
+ * @see View#onOverScrolled(int,int,int,int)
+ */
+ public void onContainerViewOverScrolled(int scrollX, int scrollY, boolean clampedX,
+ boolean clampedY) {
+ int oldX = mContainerView.getScrollX();
+ int oldY = mContainerView.getScrollY();
+
+ mScrollOffsetManager.onContainerViewOverScrolled(scrollX, scrollY, clampedX, clampedY);
+
+ if (mOverScrollGlow != null) {
+ mOverScrollGlow.pullGlow(mContainerView.getScrollX(), mContainerView.getScrollY(),
+ oldX, oldY,
+ mScrollOffsetManager.computeMaximumHorizontalScrollOffset(),
+ mScrollOffsetManager.computeMaximumVerticalScrollOffset());
+ }
+ }
+
+ /**
* @see View#computeHorizontalScrollRange()
*/
public int computeHorizontalScrollRange() {
@@ -1250,6 +1280,10 @@ public class AwContents {
(int)Math.round(event.getY(actionIndex) / mDIPScale));
}
+ if (mOverScrollGlow != null && event.getActionMasked() == MotionEvent.ACTION_UP) {
+ mOverScrollGlow.releaseAll();
+ }
+
return rv;
}
@@ -1382,7 +1416,6 @@ public class AwContents {
nativeSetVisibility(mNativeAwContents, mIsVisible);
}
-
/**
* Key for opaque state in bundle. Note this is only public for tests.
*/
@@ -1632,7 +1665,15 @@ public class AwContents {
@CalledByNative
private void didOverscroll(int deltaX, int deltaY) {
+ if (mOverScrollGlow != null) {
+ mOverScrollGlow.setOverScrollDeltas(deltaX, deltaY);
+ }
+
mScrollOffsetManager.overscrollBy(deltaX, deltaY);
+
+ if (mOverScrollGlow != null && mOverScrollGlow.isAnimating()) {
+ mContainerView.invalidate();
+ }
}
// -------------------------------------------------------------------------------------------
diff --git a/android_webview/java/src/org/chromium/android_webview/OverScrollGlow.java b/android_webview/java/src/org/chromium/android_webview/OverScrollGlow.java
new file mode 100644
index 0000000..5023c39
--- /dev/null
+++ b/android_webview/java/src/org/chromium/android_webview/OverScrollGlow.java
@@ -0,0 +1,210 @@
+// Copyright 2013 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.android_webview;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import android.widget.EdgeEffect;
+
+/**
+ * This class manages the edge glow effect when a WebView is flung or pulled beyond the edges.
+ */
+class OverScrollGlow {
+ private View mHostView;
+
+ private EdgeEffect mEdgeGlowTop;
+ private EdgeEffect mEdgeGlowBottom;
+ private EdgeEffect mEdgeGlowLeft;
+ private EdgeEffect mEdgeGlowRight;
+
+ private int mOverScrollDeltaX;
+ private int mOverScrollDeltaY;
+
+ public OverScrollGlow(View host) {
+ mHostView = host;
+ Context context = host.getContext();
+ mEdgeGlowTop = new EdgeEffect(context);
+ mEdgeGlowBottom = new EdgeEffect(context);
+ mEdgeGlowLeft = new EdgeEffect(context);
+ mEdgeGlowRight = new EdgeEffect(context);
+ }
+
+ /**
+ * Pull leftover touch scroll distance into one of the edge glows as appropriate.
+ *
+ * @param x Current X scroll offset
+ * @param y Current Y scroll offset
+ * @param oldX Old X scroll offset
+ * @param oldY Old Y scroll offset
+ * @param maxX Maximum range for horizontal scrolling
+ * @param maxY Maximum range for vertical scrolling
+ */
+ public void pullGlow(int x, int y, int oldX, int oldY, int maxX, int maxY) {
+ // Only show overscroll bars if there was no movement in any direction
+ // as a result of scrolling.
+ if (oldX == mHostView.getScrollX() && oldY == mHostView.getScrollY()) {
+ // Don't show left/right glows if we fit the whole content.
+ // Also don't show if there was vertical movement.
+ if (maxX > 0) {
+ final int pulledToX = oldX + mOverScrollDeltaX;
+ if (pulledToX < 0) {
+ mEdgeGlowLeft.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
+ if (!mEdgeGlowRight.isFinished()) {
+ mEdgeGlowRight.onRelease();
+ }
+ } else if (pulledToX > maxX) {
+ mEdgeGlowRight.onPull((float) mOverScrollDeltaX / mHostView.getWidth());
+ if (!mEdgeGlowLeft.isFinished()) {
+ mEdgeGlowLeft.onRelease();
+ }
+ }
+ mOverScrollDeltaX = 0;
+ }
+
+ if (maxY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
+ final int pulledToY = oldY + mOverScrollDeltaY;
+ if (pulledToY < 0) {
+ mEdgeGlowTop.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
+ } else if (pulledToY > maxY) {
+ mEdgeGlowBottom.onPull((float) mOverScrollDeltaY / mHostView.getHeight());
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
+ }
+ mOverScrollDeltaY = 0;
+ }
+ }
+ }
+
+ /**
+ * Absorb leftover fling velocity into one of the edge glows as appropriate.
+ *
+ * @param x Current X scroll offset
+ * @param y Current Y scroll offset
+ * @param oldX Old X scroll offset
+ * @param oldY Old Y scroll offset
+ * @param rangeX Maximum range for horizontal scrolling
+ * @param rangeY Maximum range for vertical scrolling
+ * @param currentFlingVelocity Current fling velocity
+ */
+ public void absorbGlow(int x, int y, int oldX, int oldY, int rangeX, int rangeY,
+ float currentFlingVelocity) {
+ if (rangeY > 0 || mHostView.getOverScrollMode() == View.OVER_SCROLL_ALWAYS) {
+ if (y < 0 && oldY >= 0) {
+ mEdgeGlowTop.onAbsorb((int) currentFlingVelocity);
+ if (!mEdgeGlowBottom.isFinished()) {
+ mEdgeGlowBottom.onRelease();
+ }
+ } else if (y > rangeY && oldY <= rangeY) {
+ mEdgeGlowBottom.onAbsorb((int) currentFlingVelocity);
+ if (!mEdgeGlowTop.isFinished()) {
+ mEdgeGlowTop.onRelease();
+ }
+ }
+ }
+
+ if (rangeX > 0) {
+ if (x < 0 && oldX >= 0) {
+ mEdgeGlowLeft.onAbsorb((int) currentFlingVelocity);
+ if (!mEdgeGlowRight.isFinished()) {
+ mEdgeGlowRight.onRelease();
+ }
+ } else if (x > rangeX && oldX <= rangeX) {
+ mEdgeGlowRight.onAbsorb((int) currentFlingVelocity);
+ if (!mEdgeGlowLeft.isFinished()) {
+ mEdgeGlowLeft.onRelease();
+ }
+ }
+ }
+ }
+
+ /**
+ * Set touch delta values indicating the current amount of overscroll.
+ *
+ * @param deltaX
+ * @param deltaY
+ */
+ public void setOverScrollDeltas(int deltaX, int deltaY) {
+ mOverScrollDeltaX += deltaX;
+ mOverScrollDeltaY += deltaY;
+ }
+
+ /**
+ * Draw the glow effect along the sides of the widget.
+ *
+ * @param canvas Canvas to draw into, transformed into view coordinates.
+ * @param maxScrollX maximum horizontal scroll offset
+ * @param maxScrollY maximum vertical scroll offset
+ * @return true if glow effects are still animating and the view should invalidate again.
+ */
+ public boolean drawEdgeGlows(Canvas canvas, int maxScrollX, int maxScrollY) {
+ final int scrollX = mHostView.getScrollX();
+ final int scrollY = mHostView.getScrollY();
+ final int width = mHostView.getWidth();
+ int height = mHostView.getHeight();
+
+ boolean invalidateForGlow = false;
+ if (!mEdgeGlowTop.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.translate(scrollX, Math.min(0, scrollY));
+ mEdgeGlowTop.setSize(width, height);
+ invalidateForGlow |= mEdgeGlowTop.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowBottom.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.translate(-width + scrollX, Math.max(maxScrollY, scrollY) + height);
+ canvas.rotate(180, width, 0);
+ mEdgeGlowBottom.setSize(width, height);
+ invalidateForGlow |= mEdgeGlowBottom.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowLeft.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.rotate(270);
+ canvas.translate(-height - scrollY, Math.min(0, scrollX));
+ mEdgeGlowLeft.setSize(height, width);
+ invalidateForGlow |= mEdgeGlowLeft.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowRight.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.rotate(90);
+ canvas.translate(scrollY, -(Math.max(scrollX, maxScrollX) + width));
+ mEdgeGlowRight.setSize(height, width);
+ invalidateForGlow |= mEdgeGlowRight.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ return invalidateForGlow;
+ }
+
+ /**
+ * @return True if any glow is still animating
+ */
+ public boolean isAnimating() {
+ return (!mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished() ||
+ !mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished());
+ }
+
+ /**
+ * Release all glows from any touch pulls in progress.
+ */
+ public void releaseAll() {
+ mEdgeGlowTop.onRelease();
+ mEdgeGlowBottom.onRelease();
+ mEdgeGlowLeft.onRelease();
+ mEdgeGlowRight.onRelease();
+ }
+}