diff options
author | Adam Powell <adamp@google.com> | 2010-08-31 11:25:47 -0700 |
---|---|---|
committer | Adam Powell <adamp@google.com> | 2010-09-01 11:56:56 -0700 |
commit | 230269d43bccccefdcb219c74c96a63ae04f4af9 (patch) | |
tree | 9f5c9d8d678f5a9701b8f93600a62b0cdd249016 /core | |
parent | 1751086360056bc60d00f2ed2988bc82be9e7bd9 (diff) | |
download | frameworks_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.java | 228 | ||||
-rw-r--r-- | core/java/android/widget/EdgeGlow.java | 2 | ||||
-rw-r--r-- | core/java/android/widget/OverScroller.java | 2 |
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; |