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

Commit f63c52ac authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Add scrolling editable text with a finger drag."

parents 4d2ece12 f70276a2
Loading
Loading
Loading
Loading
+4 −33
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@
package android.webkit;

import android.content.Context;
import android.graphics.Rect;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
@@ -41,13 +40,10 @@ class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
    private boolean mIsAutoFillProfileSet;
    private Handler mHandler;
    private int mQueryId;
    private Rect mNodeBounds = new Rect();
    private int mNodeLayerId;
    private ListPopupWindow mPopup;
    private Filter mFilter;
    private CharSequence mText;
    private ListAdapter mAdapter;
    private boolean mIsFocused;
    private View mAnchor;
    private WebViewClassic.WebViewInputConnection mInputConnection;
    private WebViewClassic mWebView;
@@ -102,13 +98,6 @@ class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
        return false;
    }

    public void setFocused(boolean isFocused) {
        mIsFocused = isFocused;
        if (!mIsFocused) {
            mPopup.dismiss();
        }
    }

    public void setText(CharSequence text) {
        mText = text;
        if (mFilter != null) {
@@ -139,20 +128,14 @@ class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
        resetRect();
    }

    public void setNodeBounds(Rect nodeBounds, int layerId) {
        mNodeBounds.set(nodeBounds);
        mNodeLayerId = layerId;
        resetRect();
    }

    public void resetRect() {
        int left = mWebView.contentToViewX(mNodeBounds.left);
        int right = mWebView.contentToViewX(mNodeBounds.right);
        int left = mWebView.contentToViewX(mWebView.mEditTextBounds.left);
        int right = mWebView.contentToViewX(mWebView.mEditTextBounds.right);
        int width = right - left;
        mPopup.setWidth(width);

        int bottom = mWebView.contentToViewY(mNodeBounds.bottom);
        int top = mWebView.contentToViewY(mNodeBounds.top);
        int bottom = mWebView.contentToViewY(mWebView.mEditTextBounds.bottom);
        int top = mWebView.contentToViewY(mWebView.mEditTextBounds.top);
        int height = bottom - top;

        AbsoluteLayout.LayoutParams lp =
@@ -178,13 +161,6 @@ class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
        }
    }

    public void scrollDelta(int layerId, int dx, int dy) {
        if (layerId == mNodeLayerId) {
            mNodeBounds.offset(dx, dy);
            resetRect();
        }
    }

    // AdapterView.OnItemClickListener implementation
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -230,11 +206,6 @@ class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {

    @Override
    public void onFilterComplete(int count) {
        if (!mIsFocused) {
            mPopup.dismiss();
            return;
        }

        boolean showDropDown = (count > 0) &&
                (mInputConnection.getIsAutoFillable() || mText.length() > 0);
        if (showDropDown) {
+116 −10
Original line number Diff line number Diff line
@@ -71,6 +71,8 @@ import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
import android.view.Display;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.HapticFeedbackConstants;
import android.view.HardwareCanvas;
@@ -114,6 +116,7 @@ import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.OverScroller;
import android.widget.PopupWindow;
import android.widget.Scroller;
import android.widget.TextView;
import android.widget.Toast;

@@ -802,6 +805,51 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
        }
    }

    private class TextScrollListener extends SimpleOnGestureListener {
        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2,
                float velocityX, float velocityY) {
            int maxScrollX = mEditTextContent.width() -
                    mEditTextBounds.width();
            int maxScrollY = mEditTextContent.height() -
                    mEditTextBounds.height();

            int contentVelocityX = viewToContentDimension((int)-velocityX);
            int contentVelocityY = viewToContentDimension((int)-velocityY);
            mEditTextScroller.fling(-mEditTextContent.left,
                    -mEditTextContent.top,
                    contentVelocityX, contentVelocityY,
                    0, maxScrollX, 0, maxScrollY);
            return true;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
                float distanceX, float distanceY) {
            // Scrollable edit text. Scroll it.
            int newScrollX = deltaToTextScroll(
                    -mEditTextContent.left, mEditTextContent.width(),
                    mEditTextBounds.width(),
                    (int) distanceX);
            int newScrollY = deltaToTextScroll(
                    -mEditTextContent.top, mEditTextContent.height(),
                    mEditTextBounds.height(),
                    (int) distanceY);
            scrollEditText(newScrollX, newScrollY);
            return true;
        }

        private int deltaToTextScroll(int oldScroll, int contentSize,
                int boundsSize, int delta) {
            int newScroll = oldScroll +
                    viewToContentDimension(delta);
            int maxScroll = contentSize - boundsSize;
            newScroll = Math.min(maxScroll, newScroll);
            newScroll = Math.max(0, newScroll);
            return newScroll;
        }
    }

    // The listener to capture global layout change event.
    private InnerGlobalLayoutListener mGlobalLayoutListener = null;

@@ -829,7 +877,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
    WebViewInputConnection mInputConnection = null;
    private int mFieldPointer;
    private PastePopupWindow mPasteWindow;
    AutoCompletePopup mAutoCompletePopup;
    private AutoCompletePopup mAutoCompletePopup;
    private GestureDetector mGestureDetector;
    Rect mEditTextBounds = new Rect();
    Rect mEditTextContent = new Rect();
    int mEditTextLayerId;
    boolean mIsEditingText = false;

    private static class OnTrimMemoryListener implements ComponentCallbacks2 {
        private static OnTrimMemoryListener sInstance = null;
@@ -985,6 +1038,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc

    // true when the touch movement exceeds the slop
    private boolean mConfirmMove;
    private boolean mTouchInEditText;

    // if true, touch events will be first processed by WebCore, if prevent
    // default is not set, the UI will continue handle them.
@@ -1033,6 +1087,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
    // pages with the space bar, in pixels.
    private static final int PAGE_SCROLL_OVERLAP = 24;

    // Time between successive calls to text scroll fling animation
    private static final int TEXT_SCROLL_ANIMATION_DELAY_MS = 16;

    /**
     * These prevent calling requestLayout if either dimension is fixed. This
     * depends on the layout parameters and the measure specs.
@@ -1066,6 +1123,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc

    // Used by OverScrollGlow
    OverScroller mScroller;
    Scroller mEditTextScroller;

    private boolean mInOverScrollMode = false;
    private static Paint mOverScrollBackground;
@@ -1195,6 +1253,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
    static final int RELOCATE_AUTO_COMPLETE_POPUP       = 146;
    static final int FOCUS_NODE_CHANGED                 = 147;
    static final int AUTOFILL_FORM                      = 148;
    static final int ANIMATE_TEXT_SCROLL                = 149;

    private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
    private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
@@ -1429,6 +1488,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
        }

        mAutoFillData = new WebViewCore.AutoFillData();
        mGestureDetector = new GestureDetector(mContext, new TextScrollListener());
        mEditTextScroller = new Scroller(context);
    }

    // === START: WebView Proxy binding ===
@@ -3915,8 +3976,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                mSelectCursorExtent.offset(dx, dy);
            }
        }
        if (mAutoCompletePopup != null) {
            mAutoCompletePopup.scrollDelta(mCurrentScrollingLayerId, dx, dy);
        if (mAutoCompletePopup != null &&
                mCurrentScrollingLayerId == mEditTextLayerId) {
            mEditTextBounds.offset(dx, dy);
            mAutoCompletePopup.resetRect();
        }
        nativeScrollLayer(mCurrentScrollingLayerId, x, y);
        mScrollingLayerRect.left = x;
@@ -5943,6 +6006,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                mPreventDefault = PREVENT_DEFAULT_NO;
                mConfirmMove = false;
                mInitialHitTestResult = null;
                if (!mEditTextScroller.isFinished()) {
                    mEditTextScroller.abortAnimation();
                }
                if (!mScroller.isFinished()) {
                    // stop the current scroll animation, but if this is
                    // the start of a fling, allow it to add to the current
@@ -6080,6 +6146,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                    }
                }
                startTouch(x, y, eventTime);
                if (mIsEditingText) {
                    mTouchInEditText = mEditTextBounds.contains(contentX, contentY);
                    mGestureDetector.onTouchEvent(ev);
                }
                break;
            }
            case MotionEvent.ACTION_MOVE: {
@@ -6113,6 +6183,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                        invalidate();
                    }
                    break;
                } else if (mConfirmMove && mTouchInEditText) {
                    ViewParent parent = mWebView.getParent();
                    if (parent != null) {
                        parent.requestDisallowInterceptTouchEvent(true);
                    }
                    mGestureDetector.onTouchEvent(ev);
                    break;
                }

                // pass the touch events from UI thread to WebCore thread
@@ -6282,6 +6359,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                break;
            }
            case MotionEvent.ACTION_UP: {
                mGestureDetector.onTouchEvent(ev);
                if (mTouchInEditText && mConfirmMove) {
                    break; // We've been scrolling the edit text.
                }
                // pass the touch events from UI thread to WebCore thread
                if (shouldForwardTouchEvent()) {
                    TouchEventData ted = new TouchEventData();
@@ -8328,8 +8409,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                    break;

                case FOCUS_NODE_CHANGED:
                    if (mAutoCompletePopup != null) {
                        mAutoCompletePopup.setFocused(msg.arg1 == mFieldPointer);
                    mIsEditingText = (msg.arg1 == mFieldPointer);
                    if (mAutoCompletePopup != null && !mIsEditingText) {
                        mAutoCompletePopup.clearAdapter();
                    }
                    // fall through to HIT_TEST_RESULT
                case HIT_TEST_RESULT:
@@ -8375,11 +8457,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                        mFieldPointer = initData.mFieldPointer;
                        mInputConnection.initEditorInfo(initData);
                        mInputConnection.setTextAndKeepSelection(initData.mText);
                        nativeMapLayerRect(mNativeClass, initData.mNodeLayerId,
                                initData.mNodeBounds);
                        mAutoCompletePopup.setNodeBounds(initData.mNodeBounds,
                                initData.mNodeLayerId);
                        mAutoCompletePopup.setText(mInputConnection.getEditable());
                        mEditTextBounds.set(initData.mNodeBounds);
                        mEditTextLayerId = initData.mNodeLayerId;
                        nativeMapLayerRect(mNativeClass, mEditTextLayerId,
                                mEditTextBounds);
                        mEditTextContent.set(initData.mContentRect);
                        relocateAutoCompletePopup();
                    }
                    break;

@@ -8417,6 +8500,10 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
                            msg.arg1, /* unused */0);
                    break;

                case ANIMATE_TEXT_SCROLL:
                    computeEditTextScroll();
                    break;

                default:
                    super.handleMessage(msg);
                    break;
@@ -8730,6 +8817,25 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
        invalidate();
    }

    private void computeEditTextScroll() {
        if (mEditTextScroller.computeScrollOffset()) {
            scrollEditText(mEditTextScroller.getCurrX(),
                    mEditTextScroller.getCurrY());
        }
    }

    private void scrollEditText(int scrollX, int scrollY) {
        // Scrollable edit text. Scroll it.
        float maxScrollX = (float)(mEditTextContent.width() -
                mEditTextBounds.width());
        float scrollPercentX = ((float)scrollX)/maxScrollX;
        mEditTextContent.offsetTo(-scrollX, -scrollY);
        mWebViewCore.sendMessageAtFrontOfQueue(EventHub.SCROLL_TEXT_INPUT, 0,
                scrollY, (Float)scrollPercentX);
        mPrivateHandler.sendEmptyMessageDelayed(ANIMATE_TEXT_SCROLL,
                TEXT_SCROLL_ANIMATION_DELAY_MS);
    }

    // Class used to use a dropdown for a <select> element
    private class InvokeListBox implements Runnable {
        // Whether the listbox allows multiple selection.
+23 −41
Original line number Diff line number Diff line
@@ -951,36 +951,19 @@ public final class WebViewCore {
    }

    static class TextFieldInitData {
        public TextFieldInitData(int fieldPointer,
                String text, int type, boolean isSpellCheckEnabled,
                boolean autoComplete, boolean isTextFieldNext,
                boolean isTextFieldPrev, String name, String label,
                int maxLength, Rect nodeBounds, int nodeLayerId) {
            mFieldPointer = fieldPointer;
            mText = text;
            mType = type;
            mIsAutoCompleteEnabled = autoComplete;
            mIsSpellCheckEnabled = isSpellCheckEnabled;
            mIsTextFieldNext = isTextFieldNext;
            mIsTextFieldPrev = isTextFieldPrev;
            mName = name;
            mLabel = label;
            mMaxLength = maxLength;
            mNodeBounds = nodeBounds;
            mNodeLayerId = nodeLayerId;
        }
        int mFieldPointer;
        String mText;
        int mType;
        boolean mIsSpellCheckEnabled;
        boolean mIsTextFieldNext;
        boolean mIsTextFieldPrev;
        boolean mIsAutoCompleteEnabled;
        String mName;
        String mLabel;
        int mMaxLength;
        Rect mNodeBounds;
        int mNodeLayerId;
        public int mFieldPointer;
        public String mText;
        public int mType;
        public boolean mIsSpellCheckEnabled;
        public boolean mIsTextFieldNext;
        public boolean mIsTextFieldPrev;
        public boolean mIsAutoCompleteEnabled;
        public String mName;
        public String mLabel;
        public int mMaxLength;
        public Rect mNodeBounds;
        public int mNodeLayerId;
        public Rect mContentRect;
    }

    // mAction of TouchEventData can be MotionEvent.getAction() which uses the
@@ -1931,6 +1914,11 @@ public final class WebViewCore {
        mEventHub.sendMessage(Message.obtain(null, what));
    }

    void sendMessageAtFrontOfQueue(int what, int arg1, int arg2, Object obj) {
        mEventHub.sendMessageAtFrontOfQueue(Message.obtain(
                null, what, arg1, arg2, obj));
    }

    void sendMessage(int what, Object obj) {
        mEventHub.sendMessage(Message.obtain(null, what, obj));
    }
@@ -2798,23 +2786,17 @@ public final class WebViewCore {
    }

    // called by JNI
    private void initEditField(int pointer, String text, int inputType,
            boolean isSpellCheckEnabled, boolean isAutoCompleteEnabled,
            boolean nextFieldIsText, boolean prevFieldIsText, String name,
            String label, int start, int end, int selectionPtr, int maxLength,
            Rect nodeRect, int nodeLayer) {
    private void initEditField(int start, int end, int selectionPtr,
            TextFieldInitData initData) {
        if (mWebView == null) {
            return;
        }
        TextFieldInitData initData = new TextFieldInitData(pointer,
                text, inputType, isSpellCheckEnabled, isAutoCompleteEnabled,
                nextFieldIsText, prevFieldIsText, name, label, maxLength,
                nodeRect, nodeLayer);
        Message.obtain(mWebView.mPrivateHandler,
                WebViewClassic.INIT_EDIT_FIELD, initData).sendToTarget();
        Message.obtain(mWebView.mPrivateHandler,
                WebViewClassic.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID, pointer,
                0, new TextSelectionData(start, end, selectionPtr))
                WebViewClassic.REQUEST_KEYBOARD_WITH_SELECTION_MSG_ID,
                initData.mFieldPointer, 0,
                new TextSelectionData(start, end, selectionPtr))
                .sendToTarget();
    }