Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10e85ba9 authored by Android (Google) Code Review's avatar Android (Google) Code Review
Browse files

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.
parents 3cbaf008 8b97e4b0
Loading
Loading
Loading
Loading
+171 −15
Original line number Diff line number Diff line
@@ -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);
}
+32 −10
Original line number Diff line number Diff line
@@ -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());
                }
            }
            nativeSetSize(width, Math.round((float) width * h / w), w, scale,
                    w, h);
            } else {
                width = Math.max(w, mViewportWidth);
            }
            // 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;
        }
    }

@@ -1776,6 +1787,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) {