diff options
author | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-28 13:45:58 -0700 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-28 13:45:58 -0700 |
commit | 10e85ba98771608542e2fc1de9efadb07a62e1fa (patch) | |
tree | 3ec6ef1160085dc2cc6b83b25792030de59c918d /core | |
parent | 3cbaf0087f4bbed5a5f711d1a588e5ec9d369005 (diff) | |
parent | 8b97e4b0fe4a89a76b47a8df422d0d3ea5b70754 (diff) | |
download | frameworks_base-10e85ba98771608542e2fc1de9efadb07a62e1fa.zip frameworks_base-10e85ba98771608542e2fc1de9efadb07a62e1fa.tar.gz frameworks_base-10e85ba98771608542e2fc1de9efadb07a62e1fa.tar.bz2 |
Merge change 8437
* changes:
Re-add double tap to the Browser. It only works if WebView uses wide viewport. It is also controlled by ENABLE_DOUBLETAP_ZOOM flag. Currently the default is on.
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/webkit/WebView.java | 186 | ||||
-rw-r--r-- | core/java/android/webkit/WebViewCore.java | 42 |
2 files changed, 203 insertions, 25 deletions
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 19df87f..358fc9e 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -351,6 +351,9 @@ public class WebView extends AbsoluteLayout VelocityTracker mVelocityTracker; private int mMaximumFling; + // use this flag to control whether enabling the new double tap zoom + static final boolean ENABLE_DOUBLETAP_ZOOM = true; + /** * Touch mode */ @@ -370,6 +373,7 @@ public class WebView extends AbsoluteLayout private static final int SCROLL_ZOOM_OUT = 11; private static final int LAST_SCROLL_ZOOM = 11; // end of touch mode values specific to scale+scroll + private static final int TOUCH_DOUBLE_TAP_MODE = 12; // Whether to forward the touch events to WebCore private boolean mForwardTouchEvents = false; @@ -394,6 +398,8 @@ public class WebView extends AbsoluteLayout */ // pre-computed square of ViewConfiguration.getScaledTouchSlop() private int mTouchSlopSquare; + // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop() + private int mDoubleTapSlopSquare; // pre-computed density adjusted navigation slop private int mNavSlop; // This should be ViewConfiguration.getTapTimeout() @@ -450,6 +456,7 @@ public class WebView extends AbsoluteLayout private static final int NEVER_REMEMBER_PASSWORD = 2; private static final int SWITCH_TO_SHORTPRESS = 3; private static final int SWITCH_TO_LONGPRESS = 4; + private static final int RELEASE_SINGLE_TAP = 5; private static final int REQUEST_FORM_DATA = 6; private static final int SWITCH_TO_CLICK = 7; private static final int RESUME_WEBCORE_UPDATE = 8; @@ -482,7 +489,7 @@ public class WebView extends AbsoluteLayout "NEVER_REMEMBER_PASSWORD", // = 2; "SWITCH_TO_SHORTPRESS", // = 3; "SWITCH_TO_LONGPRESS", // = 4; - "5", + "RELEASE_SINGLE_TAP", // = 5; "REQUEST_FORM_DATA", // = 6; "SWITCH_TO_CLICK", // = 7; "RESUME_WEBCORE_UPDATE", // = 8; @@ -521,6 +528,16 @@ public class WebView extends AbsoluteLayout // initial scale in percent. 0 means using default. private int mInitialScale = 0; + // while in the zoom overview mode, the page's width is fully fit to the + // current window. The page is alive, in another words, you can click to + // follow the links. Double tap will toggle between zoom overview mode and + // the last zoom scale. + boolean mInZoomOverview = false; + // ideally mZoomOverviewWidth should be mContentWidth. But sites like espn, + // engadget always have wider mContentWidth no matter what viewport size is. + int mZoomOverviewWidth = 0; + float mLastScale; + // default scale. Depending on the display density. static int DEFAULT_SCALE_PERCENT; private float mDefaultScale; @@ -762,9 +779,11 @@ public class WebView extends AbsoluteLayout setLongClickable(true); final ViewConfiguration configuration = ViewConfiguration.get(getContext()); - final int slop = configuration.getScaledTouchSlop(); + int slop = configuration.getScaledTouchSlop(); mTouchSlopSquare = slop * slop; mMinLockSnapReverseDistance = slop; + slop = configuration.getScaledDoubleTapSlop(); + mDoubleTapSlopSquare = slop * slop; final float density = getContext().getResources().getDisplayMetrics().density; // use one line height, 16 based on our current default font, for how // far we allow a touch be away from the edge of a link @@ -1124,6 +1143,9 @@ public class WebView extends AbsoluteLayout b.putInt("scrollX", mScrollX); b.putInt("scrollY", mScrollY); b.putFloat("scale", mActualScale); + if (mInZoomOverview) { + b.putFloat("lastScale", mLastScale); + } return true; } return false; @@ -1168,6 +1190,13 @@ public class WebView extends AbsoluteLayout // onSizeChanged() is called, the rest will be set // correctly mActualScale = scale; + float lastScale = b.getFloat("lastScale", -1.0f); + if (lastScale > 0) { + mInZoomOverview = true; + mLastScale = lastScale; + } else { + mInZoomOverview = false; + } invalidate(); return true; } @@ -3060,6 +3089,11 @@ public class WebView extends AbsoluteLayout float y = mLastTouchY + (float) (mScrollY - lp.y); mWebTextView.fakeTouchEvent(x, y); } + if (mInZoomOverview) { + // if in zoom overview mode, call doDoubleTap() to bring it back + // to normal mode so that user can enter text. + doDoubleTap(); + } } else { // used by plugins imm.showSoftInput(this, 0); @@ -3634,7 +3668,9 @@ public class WebView extends AbsoluteLayout // update mMinZoomScale if the minimum zoom scale is not fixed if (!mMinZoomScaleFixed) { mMinZoomScale = (float) getViewWidth() - / Math.max(ZOOM_OUT_WIDTH, mContentWidth); + / Math.max(ZOOM_OUT_WIDTH, mDrawHistory ? mHistoryPicture + .getWidth() : (mZoomOverviewWidth > 0 ? + mZoomOverviewWidth : mContentWidth)); } // we always force, in case our height changed, in which case we still @@ -3755,6 +3791,15 @@ public class WebView extends AbsoluteLayout nativeMoveSelection(viewToContent(mSelectX) , viewToContent(mSelectY), false); mTouchSelection = mExtendSelection = true; + } else if (mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) { + mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP); + if (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare) { + mTouchMode = TOUCH_DOUBLE_TAP_MODE; + } else { + // commit the short press action for the previous tap + doShortPress(); + // continue, mTouchMode should be still TOUCH_INIT_MODE + } } else { mTouchMode = TOUCH_INIT_MODE; mPreventDrag = mForwardTouchEvents; @@ -3764,7 +3809,8 @@ public class WebView extends AbsoluteLayout } } // Trigger the link - if (mTouchMode == TOUCH_INIT_MODE) { + if (mTouchMode == TOUCH_INIT_MODE + || mTouchMode == TOUCH_DOUBLE_TAP_MODE) { mPrivateHandler.sendMessageDelayed(mPrivateHandler .obtainMessage(SWITCH_TO_SHORTPRESS), TAP_TIMEOUT); } @@ -3810,7 +3856,8 @@ public class WebView extends AbsoluteLayout if (mTouchMode == TOUCH_SHORTPRESS_MODE || mTouchMode == TOUCH_SHORTPRESS_START_MODE) { mPrivateHandler.removeMessages(SWITCH_TO_LONGPRESS); - } else if (mTouchMode == TOUCH_INIT_MODE) { + } else if (mTouchMode == TOUCH_INIT_MODE + || mTouchMode == TOUCH_DOUBLE_TAP_MODE) { mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); } @@ -3836,7 +3883,7 @@ public class WebView extends AbsoluteLayout .sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0); } WebSettings settings = getSettings(); - if (settings.supportZoom() + if (settings.supportZoom() && !mInZoomOverview && settings.getBuiltInZoomControls() && !mZoomButtonsController.isVisible() && (canZoomScrollOut() || @@ -3905,7 +3952,7 @@ public class WebView extends AbsoluteLayout mUserScroll = true; } - if (!getSettings().getBuiltInZoomControls()) { + if (!getSettings().getBuiltInZoomControls() && !mInZoomOverview) { boolean showPlusMinus = mMinZoomScale < mMaxZoomScale; boolean showMagnify = canZoomScrollOut(); if (mZoomControls != null && (showPlusMinus || showMagnify)) { @@ -3929,7 +3976,22 @@ public class WebView extends AbsoluteLayout case MotionEvent.ACTION_UP: { mLastTouchUpTime = eventTime; switch (mTouchMode) { + case TOUCH_DOUBLE_TAP_MODE: // double tap + mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); + doDoubleTap(); + break; case TOUCH_INIT_MODE: // tap + if (ENABLE_DOUBLETAP_ZOOM) { + mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); + if (!mPreventDrag) { + mPrivateHandler.sendMessageDelayed( + mPrivateHandler.obtainMessage( + RELEASE_SINGLE_TAP), + ViewConfiguration.getDoubleTapTimeout()); + } + break; + } + // fall through case TOUCH_SHORTPRESS_START_MODE: case TOUCH_SHORTPRESS_MODE: mPrivateHandler.removeMessages(SWITCH_TO_SHORTPRESS); @@ -4365,6 +4427,9 @@ public class WebView extends AbsoluteLayout mInvInitialZoomScale = 1.0f / oldScale; mInvFinalZoomScale = 1.0f / mActualScale; mZoomScale = mActualScale; + if (!mInZoomOverview) { + mLastScale = scale; + } invalidate(); return true; } else { @@ -4470,6 +4535,9 @@ public class WebView extends AbsoluteLayout public boolean zoomIn() { // TODO: alternatively we can disallow this during draw history mode switchOutDrawHistory(); + // Center zooming to the center of the screen. + mZoomCenterX = getViewWidth() * .5f; + mZoomCenterY = getViewHeight() * .5f; return zoomWithPreview(mActualScale * 1.25f); } @@ -4480,6 +4548,9 @@ public class WebView extends AbsoluteLayout public boolean zoomOut() { // TODO: alternatively we can disallow this during draw history mode switchOutDrawHistory(); + // Center zooming to the center of the screen. + mZoomCenterX = getViewWidth() * .5f; + mZoomCenterY = getViewHeight() * .5f; return zoomWithPreview(mActualScale * 0.8f); } @@ -4571,6 +4642,50 @@ public class WebView extends AbsoluteLayout } } + private void doDoubleTap() { + if (mWebViewCore.getSettings().getUseWideViewPort() == false) { + return; + } + mZoomCenterX = mLastTouchX; + mZoomCenterY = mLastTouchY; + mInZoomOverview = !mInZoomOverview; + if (mInZoomOverview) { + float newScale = (float) getViewWidth() + / (mZoomOverviewWidth > 0 ? mZoomOverviewWidth + : mContentWidth); + if (Math.abs(newScale - mActualScale) < 0.01) { + mInZoomOverview = !mInZoomOverview; + // as it is already full screen, do nothing. + return; + } + if (getSettings().getBuiltInZoomControls()) { + if (mZoomButtonsController.isVisible()) { + mZoomButtonsController.setVisible(false); + } + } else { + if (mZoomControlRunnable != null) { + mPrivateHandler.removeCallbacks(mZoomControlRunnable); + } + if (mZoomControls != null) { + mZoomControls.hide(); + } + } + zoomWithPreview(newScale); + } else { + // mLastTouchX and mLastTouchY are the point in the current viewport + int contentX = viewToContent((int) mLastTouchX + mScrollX); + int contentY = viewToContent((int) mLastTouchY + mScrollY); + int left = nativeGetBlockLeftEdge(contentX, contentY); + if (left != NO_LEFTEDGE) { + // add a 5pt padding to the left edge. Re-calculate the zoom + // center so that the new scroll x will be on the left edge. + mZoomCenterX = left < 5 ? 0 : (left - 5) * mLastScale + * mActualScale / (mLastScale - mActualScale); + } + zoomWithPreview(mLastScale); + } + } + // Called by JNI to handle a touch on a node representing an email address, // address, or phone number private void overrideLoading(String url) { @@ -4791,6 +4906,8 @@ public class WebView extends AbsoluteLayout if (mTouchMode == TOUCH_INIT_MODE) { mTouchMode = TOUCH_SHORTPRESS_START_MODE; updateSelection(); + } else if (mTouchMode == TOUCH_DOUBLE_TAP_MODE) { + mTouchMode = TOUCH_DONE_MODE; } break; } @@ -4802,6 +4919,13 @@ public class WebView extends AbsoluteLayout } break; } + case RELEASE_SINGLE_TAP: { + if (!mPreventDrag) { + mTouchMode = TOUCH_DONE_MODE; + doShortPress(); + } + break; + } case SWITCH_TO_CLICK: // The user clicked with the trackball, and did not click a // second time, so perform the action of a trackball single @@ -4854,6 +4978,7 @@ public class WebView extends AbsoluteLayout break; case NEW_PICTURE_MSG_ID: // called for new content + final int viewWidth = getViewWidth(); final WebViewCore.DrawData draw = (WebViewCore.DrawData) msg.obj; final Point viewSize = draw.mViewPoint; @@ -4861,16 +4986,12 @@ public class WebView extends AbsoluteLayout // use the same logic in sendViewSizeZoom() to make sure // the mZoomScale has matched the viewSize so that we // can clear mZoomScale - if (Math.round(getViewWidth() / mZoomScale) == viewSize.x) { + if (Math.round(viewWidth / mZoomScale) == viewSize.x) { mZoomScale = 0; mWebViewCore.sendMessage(EventHub.SET_SNAP_ANCHOR, 0, 0); } } - if (!mMinZoomScaleFixed) { - mMinZoomScale = (float) getViewWidth() - / Math.max(ZOOM_OUT_WIDTH, draw.mWidthHeight.x); - } // We update the layout (i.e. request a layout from the // view system) if the last view size that we sent to // WebCore matches the view size of the picture we just @@ -4888,6 +5009,25 @@ public class WebView extends AbsoluteLayout if (mPictureListener != null) { mPictureListener.onNewPicture(WebView.this, capturePicture()); } + if (mWebViewCore.getSettings().getUseWideViewPort()) { + mZoomOverviewWidth = Math.max(draw.mMinPrefWidth, + draw.mViewPoint.x); + } + if (!mMinZoomScaleFixed) { + mMinZoomScale = (float) viewWidth + / Math.max(ZOOM_OUT_WIDTH, + mZoomOverviewWidth > 0 ? mZoomOverviewWidth + : mContentWidth); + } + if (!mDrawHistory && mInZoomOverview) { + // fit the content width to the current view. Ignore + // the rounding error case. + if (Math.abs((viewWidth * mInvActualScale) + - mZoomOverviewWidth) > 1) { + zoomWithPreview((float) viewWidth + / mZoomOverviewWidth); + } + } break; case WEBCORE_INITIALIZED_MSG_ID: // nativeCreate sets mNativeClass to a non-zero value @@ -4916,7 +5056,7 @@ public class WebView extends AbsoluteLayout } } break; - case DID_FIRST_LAYOUT_MSG_ID: + case DID_FIRST_LAYOUT_MSG_ID: { if (mNativeClass == 0) { break; } @@ -4943,15 +5083,17 @@ public class WebView extends AbsoluteLayout if (width == 0) { break; } + final WebSettings settings = mWebViewCore.getSettings(); int initialScale = msg.arg1; int viewportWidth = msg.arg2; // start a new page with DEFAULT_SCALE zoom scale. float scale = mDefaultScale; + mInZoomOverview = false; if (mInitialScale > 0) { scale = mInitialScale / 100.0f; } else { - if (initialScale < 0) break; - if (mWebViewCore.getSettings().getUseWideViewPort()) { + if (initialScale == -1) break; + if (settings.getUseWideViewPort()) { // force viewSizeChanged by setting mLastWidthSent // to 0 mLastWidthSent = 0; @@ -4961,11 +5103,21 @@ public class WebView extends AbsoluteLayout // than the view width, zoom in to fill the view if (viewportWidth > 0 && viewportWidth < width) { scale = (float) width / viewportWidth; + } else { + if (settings.getUseWideViewPort()) { + mInZoomOverview = ENABLE_DOUBLETAP_ZOOM; + } } + } else if (initialScale < 0) { + // this should only happen when + // ENABLE_DOUBLETAP_ZOOM is true + mInZoomOverview = true; + scale = -initialScale / 100.0f; } else { scale = initialScale / 100.0f; } } + mLastScale = scale; setNewZoomScale(scale, false); // As we are on a new page, remove the WebTextView. This // is necessary for page loads driven by webkit, and in @@ -4973,6 +5125,7 @@ public class WebView extends AbsoluteLayout // the WebTextView was visible. clearTextEntry(); break; + } case MOVE_OUT_OF_PLUGIN: if (nativePluginEatsNavKey()) { navHandledKey(msg.arg1, 1, false, 0, true); @@ -5542,4 +5695,7 @@ public class WebView extends AbsoluteLayout private native void nativeUpdateCachedTextfield(String updatedText, int generation); private native void nativeUpdatePluginReceivesEvents(); + // return NO_LEFTEDGE means failure. + private static final int NO_LEFTEDGE = -1; + private native int nativeGetBlockLeftEdge(int x, int y); } diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 4993fcf..36c5f0c 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -96,7 +96,8 @@ final class WebViewCore { private boolean mViewportUserScalable = true; - private int mRestoredScale = WebView.DEFAULT_SCALE_PERCENT; + private int mRestoredScale = 0; + private int mRestoredScreenWidthScale = 0; private int mRestoredX = 0; private int mRestoredY = 0; @@ -1340,9 +1341,8 @@ final class WebViewCore { Log.w(LOGTAG, "skip viewSizeChanged as w is 0"); return; } - if (mSettings.getUseWideViewPort() - && (w < mViewportWidth || mViewportWidth == -1)) { - int width = mViewportWidth; + if (mSettings.getUseWideViewPort()) { + int width; if (mViewportWidth == -1) { if (mSettings.getLayoutAlgorithm() == WebSettings.LayoutAlgorithm.NORMAL) { @@ -1362,9 +1362,15 @@ final class WebViewCore { */ width = Math.max(w, nativeGetContentMinPrefWidth()); } + } else { + width = Math.max(w, mViewportWidth); } - nativeSetSize(width, Math.round((float) width * h / w), w, scale, - w, h); + // while in zoom overview mode, the text are wrapped to the screen + // width matching mWebView.mLastScale. So that we don't trigger + // re-flow while toggling between overview mode and normal mode. + nativeSetSize(width, Math.round((float) width * h / w), + Math.round(mWebView.mInZoomOverview ? w * scale + / mWebView.mLastScale : w), scale, w, h); } else { nativeSetSize(w, h, w, scale, w, h); } @@ -1409,6 +1415,7 @@ final class WebViewCore { public Region mInvalRegion; public Point mViewPoint; public Point mWidthHeight; + public int mMinPrefWidth; } private void webkitDraw() { @@ -1424,6 +1431,9 @@ final class WebViewCore { // Send the native view size that was used during the most recent // layout. draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight); + if (WebView.ENABLE_DOUBLETAP_ZOOM && mSettings.getUseWideViewPort()) { + draw.mMinPrefWidth = nativeGetContentMinPrefWidth(); + } if (DebugFlags.WEB_VIEW_CORE) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); Message.obtain(mWebView.mPrivateHandler, WebView.NEW_PICTURE_MSG_ID, draw).sendToTarget(); @@ -1734,9 +1744,10 @@ final class WebViewCore { if (mRestoredScale > 0) { Message.obtain(mWebView.mPrivateHandler, - WebView.DID_FIRST_LAYOUT_MSG_ID, mRestoredScale, 0, + WebView.DID_FIRST_LAYOUT_MSG_ID, + mRestoredScreenWidthScale > 0 ? + -mRestoredScreenWidthScale : mRestoredScale, 0, scaleLimit).sendToTarget(); - mRestoredScale = 0; } else { // if standardLoad is true, use mViewportInitialScale, otherwise // pass -1 to the WebView to indicate no change of the scale. @@ -1764,8 +1775,8 @@ final class WebViewCore { } } - // reset restored offset - mRestoredX = mRestoredY = 0; + // reset restored offset, scale + mRestoredX = mRestoredY = mRestoredScale = mRestoredScreenWidthScale = 0; } } @@ -1777,6 +1788,17 @@ final class WebViewCore { } // called by JNI + private void restoreScreenWidthScale(int scale) { + if (!WebView.ENABLE_DOUBLETAP_ZOOM || !mSettings.getUseWideViewPort()) { + return; + } + + if (mBrowserFrame.firstLayoutDone() == false) { + mRestoredScreenWidthScale = scale; + } + } + + // called by JNI private void needTouchEvents(boolean need) { if (mWebView != null) { Message.obtain(mWebView.mPrivateHandler, |