summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorAdam Powell <adamp@google.com>2010-08-31 11:25:47 -0700
committerAdam Powell <adamp@google.com>2010-09-01 11:56:56 -0700
commit230269d43bccccefdcb219c74c96a63ae04f4af9 (patch)
tree9f5c9d8d678f5a9701b8f93600a62b0cdd249016 /core
parent1751086360056bc60d00f2ed2988bc82be9e7bd9 (diff)
downloadframeworks_base-230269d43bccccefdcb219c74c96a63ae04f4af9.zip
frameworks_base-230269d43bccccefdcb219c74c96a63ae04f4af9.tar.gz
frameworks_base-230269d43bccccefdcb219c74c96a63ae04f4af9.tar.bz2
DO NOT MERGE Integrate edge effects into WebView.
TODO Effect for scaling gestures; asset/polish tweaks. Change-Id: Ifbc201cb64e0610dbc92a7c57ba0d3a4ee686c43
Diffstat (limited to 'core')
-rw-r--r--core/java/android/webkit/WebView.java228
-rw-r--r--core/java/android/widget/EdgeGlow.java2
-rw-r--r--core/java/android/widget/OverScroller.java2
3 files changed, 203 insertions, 29 deletions
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 087d4c3..7898083 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -16,13 +16,16 @@
package android.webkit;
+import com.android.internal.R;
+
import android.annotation.Widget;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
-import android.content.Intent;
import android.content.DialogInterface.OnCancelListener;
+import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
import android.database.DataSetObserver;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -30,7 +33,6 @@ import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Interpolator;
-import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Picture;
import android.graphics.Point;
@@ -39,8 +41,8 @@ import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
-import android.net.http.SslCertificate;
import android.net.Uri;
+import android.net.http.SslCertificate;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -74,8 +76,10 @@ import android.webkit.WebViewCore.TouchEventData;
import android.widget.AbsoluteLayout;
import android.widget.Adapter;
import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckedTextView;
+import android.widget.EdgeGlow;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ListView;
@@ -83,17 +87,15 @@ import android.widget.OverScroller;
import android.widget.Toast;
import android.widget.ZoomButtonsController;
import android.widget.ZoomControls;
-import android.widget.AdapterView.OnItemClickListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.IOException;
import java.net.URLDecoder;
import java.util.ArrayList;
-import java.util.List;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -757,6 +759,27 @@ public class WebView extends AbsoluteLayout
private int mHorizontalScrollBarMode = SCROLLBAR_AUTO;
private int mVerticalScrollBarMode = SCROLLBAR_AUTO;
+ /**
+ * Max distance to overscroll by in pixels.
+ * This how far content can be pulled beyond its normal bounds by the user.
+ */
+ private int mOverscrollDistance;
+
+ /**
+ * Max distance to overfling by in pixels.
+ * This is how far flinged content can move beyond the end of its normal bounds.
+ */
+ private int mOverflingDistance;
+
+ /*
+ * These manage the edge glow effect when flung or pulled beyond the edges.
+ * If one is not null, all are not null. Checking one for null is as good as checking each.
+ */
+ private EdgeGlow mEdgeGlowTop;
+ private EdgeGlow mEdgeGlowBottom;
+ private EdgeGlow mEdgeGlowLeft;
+ private EdgeGlow mEdgeGlowRight;
+
// Used to match key downs and key ups
private boolean mGotKeyDown;
@@ -986,7 +1009,6 @@ public class WebView extends AbsoluteLayout
setFocusableInTouchMode(true);
setClickable(true);
setLongClickable(true);
- setOverscrollMode(OVERSCROLL_NEVER);
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
int slop = configuration.getScaledTouchSlop();
@@ -1009,6 +1031,29 @@ public class WebView extends AbsoluteLayout
mMaxZoomScale = DEFAULT_MAX_ZOOM_SCALE;
mMinZoomScale = DEFAULT_MIN_ZOOM_SCALE;
mMaximumFling = configuration.getScaledMaximumFlingVelocity();
+ mOverscrollDistance = configuration.getScaledOverscrollDistance();
+ mOverflingDistance = configuration.getScaledOverflingDistance();
+ }
+
+ @Override
+ public void setOverscrollMode(int mode) {
+ super.setOverscrollMode(mode);
+ if (mode != OVERSCROLL_NEVER) {
+ if (mEdgeGlowTop == null) {
+ final Resources res = getContext().getResources();
+ final Drawable edge = res.getDrawable(R.drawable.edge_light);
+ final Drawable glow = res.getDrawable(R.drawable.overscroll_glow);
+ mEdgeGlowTop = new EdgeGlow(edge, glow);
+ mEdgeGlowBottom = new EdgeGlow(edge, glow);
+ mEdgeGlowLeft = new EdgeGlow(edge, glow);
+ mEdgeGlowRight = new EdgeGlow(edge, glow);
+ }
+ } else {
+ mEdgeGlowTop = null;
+ mEdgeGlowBottom = null;
+ mEdgeGlowLeft = null;
+ mEdgeGlowRight = null;
+ }
}
/* package */void updateDefaultZoomDensity(int zoomDensity) {
@@ -2500,6 +2545,9 @@ public class WebView extends AbsoluteLayout
protected void onDrawVerticalScrollBar(Canvas canvas,
Drawable scrollBar,
int l, int t, int r, int b) {
+ if (mScrollY < 0) {
+ t -= mScrollY;
+ }
scrollBar.setBounds(l, t + getVisibleTitleHeight(), r, b);
scrollBar.draw(canvas);
}
@@ -2518,6 +2566,12 @@ public class WebView extends AbsoluteLayout
if (scrollY < 0 || scrollY > computeMaxScrollY()) {
mInOverScrollMode = true;
}
+
+ if ((clampedX && maxX > 0) || clampedY) {
+ // Hitting a scroll barrier breaks velocity; don't fling further.
+ mVelocityTracker.clear();
+ mLastVelocity = 0;
+ }
super.scrollTo(scrollX, scrollY);
}
@@ -2876,12 +2930,35 @@ public class WebView extends AbsoluteLayout
int oldY = mScrollY;
int x = mScroller.getCurrX();
int y = mScroller.getCurrY();
- postInvalidate(); // So we draw again
+ invalidate(); // So we draw again
if (oldX != x || oldY != y) {
+ final int rangeX = computeMaxScrollX();
+ final int rangeY = computeMaxScrollY();
overscrollBy(x - oldX, y - oldY, oldX, oldY,
- computeMaxScrollX(), computeMaxScrollY(),
- getViewWidth() / 3, getViewHeight() / 3, false);
+ rangeX, rangeY,
+ mOverflingDistance, mOverflingDistance, false);
+
+ if (mEdgeGlowTop != null) {
+ if (rangeY > 0 || getOverscrollMode() == OVERSCROLL_ALWAYS) {
+ if (y < 0 && oldY >= 0) {
+ mEdgeGlowTop.onAbsorb((int) mScroller.getCurrVelocity());
+ } else if (y > rangeY && oldY <= rangeY) {
+ mEdgeGlowBottom.onAbsorb((int) mScroller.getCurrVelocity());
+ }
+ }
+
+ if (rangeX > 0) {
+ if (x < 0 && oldX >= 0) {
+ mEdgeGlowLeft.onAbsorb((int) mScroller.getCurrVelocity());
+ } else if (x > rangeX && oldX <= rangeX) {
+ mEdgeGlowRight.onAbsorb((int) mScroller.getCurrVelocity());
+ }
+ }
+ }
+ }
+ if (mScroller.isFinished()) {
+ mPrivateHandler.sendEmptyMessage(RESUME_WEBCORE_PRIORITY);
}
} else {
super.computeScroll();
@@ -3292,13 +3369,8 @@ public class WebView extends AbsoluteLayout
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
if (child == mTitleBar) {
// When drawing the title bar, move it horizontally to always show
- // at the top of the WebView. While overscroll, stick the title bar
- // on the top otherwise we may have two during loading, one is drawn
- // here, another is drawn by the Browser.
+ // at the top of the WebView.
mTitleBar.offsetLeftAndRight(mScrollX - mTitleBar.getLeft());
- if (mScrollY <= 0) {
- mTitleBar.offsetTopAndBottom(mScrollY - mTitleBar.getTop());
- }
}
return super.drawChild(canvas, child, drawingTime);
}
@@ -3349,7 +3421,7 @@ public class WebView extends AbsoluteLayout
mOverScrollBorder.setColor(0xffbbbbbb);
}
- int top = getTitleHeight();
+ int top = 0;
int right = computeRealHorizontalScrollRange();
int bottom = top + computeRealVerticalScrollRange();
// first draw the background and anchor to the top of the view
@@ -3389,6 +3461,7 @@ public class WebView extends AbsoluteLayout
mScrollY + height);
mTitleShadow.draw(canvas);
}
+
if (AUTO_REDRAW_HACK && mAutoRedraw) {
invalidate();
}
@@ -3396,6 +3469,65 @@ public class WebView extends AbsoluteLayout
}
@Override
+ protected void dispatchDraw(Canvas canvas) {
+ super.dispatchDraw(canvas);
+ if (mEdgeGlowTop != null && drawEdgeGlows(canvas)) {
+ invalidate();
+ }
+ }
+
+ /**
+ * Draw the glow effect along the sides of the widget. mEdgeGlow* must be non-null.
+ *
+ * @param canvas Canvas to draw into, transformed into view coordinates.
+ * @return true if glow effects are still animating and the view should invalidate again.
+ */
+ private boolean drawEdgeGlows(Canvas canvas) {
+ final int scrollX = mScrollX;
+ final int scrollY = mScrollY;
+ final int width = getWidth();
+ int height = getHeight();
+
+ boolean invalidateForGlow = false;
+ if (!mEdgeGlowTop.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.translate(-width / 2 + scrollX, scrollY);
+ mEdgeGlowTop.setSize(width * 2, height);
+ invalidateForGlow |= mEdgeGlowTop.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowBottom.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.translate(-width / 2 - scrollX, scrollY + height);
+ canvas.rotate(180, width, 0);
+ mEdgeGlowBottom.setSize(width * 2, height);
+ invalidateForGlow |= mEdgeGlowBottom.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowLeft.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.rotate(270);
+ canvas.translate(-height * 1.5f - scrollY, scrollX);
+ mEdgeGlowLeft.setSize(height * 2, width);
+ invalidateForGlow |= mEdgeGlowLeft.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ if (!mEdgeGlowRight.isFinished()) {
+ final int restoreCount = canvas.save();
+
+ canvas.rotate(90);
+ canvas.translate(-height / 2 + scrollY, -scrollX - width);
+ mEdgeGlowRight.setSize(height * 2, width);
+ invalidateForGlow |= mEdgeGlowRight.draw(canvas);
+ canvas.restoreToCount(restoreCount);
+ }
+ return invalidateForGlow;
+ }
+
+ @Override
public void setLayoutParams(ViewGroup.LayoutParams params) {
if (params.height == LayoutParams.WRAP_CONTENT) {
mWrapContent = true;
@@ -5386,9 +5518,34 @@ public class WebView extends AbsoluteLayout
private void doDrag(int deltaX, int deltaY) {
if ((deltaX | deltaY) != 0) {
- overscrollBy(deltaX, deltaY, mScrollX, mScrollY,
- computeMaxScrollX(), computeMaxScrollY(),
- getViewWidth() / 3, getViewHeight() / 3, true);
+ final int oldX = mScrollX;
+ final int oldY = mScrollY;
+ final int rangeX = computeMaxScrollX();
+ final int rangeY = computeMaxScrollY();
+ overscrollBy(deltaX, deltaY, oldX, oldY,
+ rangeX, rangeY,
+ mOverscrollDistance, mOverscrollDistance, true);
+
+ if (mEdgeGlowTop != null) {
+ // Don't show left/right glows if we fit the whole content.
+ if (rangeX > 0) {
+ final int pulledToX = oldX + deltaX;
+ if (pulledToX < 0) {
+ mEdgeGlowLeft.onPull((float) deltaX / getWidth());
+ } else if (pulledToX > rangeX) {
+ mEdgeGlowRight.onPull((float) deltaX / getWidth());
+ }
+ }
+
+ if (rangeY > 0 || getOverscrollMode() == OVERSCROLL_ALWAYS) {
+ final int pulledToY = oldY + deltaY;
+ if (pulledToY < 0) {
+ mEdgeGlowTop.onPull((float) deltaY / getHeight());
+ } else if (pulledToY > rangeY) {
+ mEdgeGlowBottom.onPull((float) deltaY / getHeight());
+ }
+ }
+ }
}
if (!getSettings().getBuiltInZoomControls()) {
boolean showPlusMinus = mMinZoomScale < mMaxZoomScale;
@@ -5415,6 +5572,14 @@ public class WebView extends AbsoluteLayout
mVelocityTracker.recycle();
mVelocityTracker = null;
}
+
+ // Release any pulled glows
+ if (mEdgeGlowTop != null) {
+ mEdgeGlowTop.onRelease();
+ mEdgeGlowBottom.onRelease();
+ mEdgeGlowLeft.onRelease();
+ mEdgeGlowRight.onRelease();
+ }
}
private void cancelTouch() {
@@ -5428,6 +5593,15 @@ public class WebView extends AbsoluteLayout
mVelocityTracker.recycle();
mVelocityTracker = null;
}
+
+ // Release any pulled glows
+ if (mEdgeGlowTop != null) {
+ mEdgeGlowTop.onRelease();
+ mEdgeGlowBottom.onRelease();
+ mEdgeGlowLeft.onRelease();
+ mEdgeGlowRight.onRelease();
+ }
+
if (mTouchMode == TOUCH_DRAG_MODE) {
WebViewCore.resumePriority();
WebViewCore.resumeUpdatePicture(mWebViewCore);
@@ -5746,7 +5920,7 @@ public class WebView extends AbsoluteLayout
public void flingScroll(int vx, int vy) {
mScroller.fling(mScrollX, mScrollY, vx, vy, 0, computeMaxScrollX(), 0,
- computeMaxScrollY(), getViewWidth() / 3, getViewHeight() / 3);
+ computeMaxScrollY(), mOverflingDistance, mOverflingDistance);
invalidate();
}
@@ -5809,13 +5983,13 @@ public class WebView extends AbsoluteLayout
// no horizontal overscroll if the content just fits
mScroller.fling(mScrollX, mScrollY, -vx, -vy, 0, maxX, 0, maxY,
- maxX == 0 ? 0 : getViewWidth() / 3, getViewHeight() / 3);
- // TODO: duration is calculated based on velocity, if the range is
- // small, the animation will stop before duration is up. We may
- // want to calculate how long the animation is going to run to precisely
- // resume the webcore update.
+ maxX == 0 ? 0 : mOverflingDistance, mOverflingDistance);
+ // Duration is calculated based on velocity. With range boundaries and overscroll
+ // we may not know how long the final animation will take. (Hence the deprecation
+ // warning on the call below.) It's not a big deal for scroll bars but if webcore
+ // resumes during this effect we will take a performance hit. See computeScroll;
+ // we resume webcore there when the animation is finished.
final int time = mScroller.getDuration();
- mPrivateHandler.sendEmptyMessageDelayed(RESUME_WEBCORE_PRIORITY, time);
awakenScrollBars(time);
invalidate();
}
diff --git a/core/java/android/widget/EdgeGlow.java b/core/java/android/widget/EdgeGlow.java
index e2c7bca..06334a0 100644
--- a/core/java/android/widget/EdgeGlow.java
+++ b/core/java/android/widget/EdgeGlow.java
@@ -213,7 +213,7 @@ public class EdgeGlow {
final int glowHeight = mGlow.getIntrinsicHeight();
mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255));
- mGlow.setBounds(0, 0, mWidth, (int) (glowHeight * mGlowScaleY));
+ mGlow.setBounds(0, 0, mWidth, (int) (glowHeight * mGlowScaleY * 0.5f));
mGlow.draw(canvas);
mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255));
diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java
index 93900a0..78973ad 100644
--- a/core/java/android/widget/OverScroller.java
+++ b/core/java/android/widget/OverScroller.java
@@ -523,7 +523,7 @@ public class OverScroller {
// If the velocity is smaller than this value, no bounce is triggered
// when the edge limits are reached (would result in a zero pixels
// displacement anyway).
- private static final float MINIMUM_VELOCITY_FOR_BOUNCE = 140.0f;
+ private static final float MINIMUM_VELOCITY_FOR_BOUNCE = Float.MAX_VALUE;//140.0f;
// Proportion of the velocity that is preserved when the edge is reached.
private static final float DEFAULT_BOUNCE_COEFFICIENT = 0.16f;