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

Commit bb107bd6 authored by Leon Scroggins's avatar Leon Scroggins
Browse files

Many fixes to text input in the browser, particularly when moving to a new field.

Remove many instances where we are setting selection unnecessarily.  Instead, only
set the selection due to a click, touch, or inserting a character.  A touch will
now set the selection properly, rather than at the beginning/end, fixing
http://b/issue?id=1650395  Also fixes http://b/issue?id=2208188

Requires a change to external/webkit.
parent 718d69f9
Loading
Loading
Loading
Loading
+65 −49
Original line number Diff line number Diff line
@@ -84,14 +84,24 @@ import java.util.ArrayList;
    // True if the most recent drag event has caused either the TextView to
    // scroll or the web page to scroll.  Gets reset after a touch down.
    private boolean         mScrolled;
    // Gets set to true when the the IME jumps to the next textfield.  When this
    // happens, the next time the user hits a key it is okay for the focus
    // pointer to not match the WebTextView's node pointer
    // Gets set to true any time the WebTextView has focus, but the navigation
    // cache does not yet know that the focus has been changed.  This happens
    // if the user presses "Next", if the user moves the cursor to a textfield
    // and starts typing or clicks the trackball/center key, and when the user
    // touches a textfield.
    boolean                 mOkayForFocusNotToMatch;
    boolean                 mResendKeyDown;
    // Whether or not a selection change was generated from webkit.  If it was,
    // we do not need to pass the selection back to webkit.
    private boolean         mFromWebKit;
    // Whether or not a selection change was generated from the WebTextView
    // gaining focus.  If it is, we do not want to pass it to webkit.  This
    // selection comes from the MovementMethod, but we behave differently.  If
    // WebTextView gained focus from a touch, webkit will determine the
    // selection.
    private boolean         mFromFocusChange;
    // Whether or not a selection change was generated from setInputType.  We
    // do not want to pass this change to webkit.
    private boolean         mFromSetInputType;
    private boolean         mGotTouchDown;
    private boolean         mInSetTextAndKeepSelection;
    // Array to store the final character added in onTextChanged, so that its
@@ -137,11 +147,15 @@ import java.util.ArrayList;
                isArrowKey = true;
                break;
        }
        if (!isArrowKey && !mOkayForFocusNotToMatch && !mResendKeyDown
                && mWebView.nativeFocusNodePointer() != mNodePointer) {
            if (mWebView.nativeFocusNodePointer() != 0) {
                mWebView.nativeClearCursor();

        if (down) {
            if (mOkayForFocusNotToMatch) {
                if (mWebView.nativeFocusNodePointer() == mNodePointer) {
                    mOkayForFocusNotToMatch = false;
                }
            } else if (mWebView.nativeFocusNodePointer() != mNodePointer
                    && !isArrowKey) {
                mWebView.nativeClearCursor();
                // Do not call remove() here, which hides the soft keyboard.  If
                // the soft keyboard is being displayed, the user will still want
                // it there.
@@ -149,10 +163,7 @@ import java.util.ArrayList;
                mWebView.requestFocus();
                return mWebView.dispatchKeyEvent(event);
            }
        // After a jump to next textfield and the first key press, the cursor
        // and focus will once again match, so reset this value.
        mOkayForFocusNotToMatch = false;
        mResendKeyDown = false;
        }
        Spannable text = (Spannable) getText();
        int oldLength = text.length();
        // Normally the delete key's dom events are sent via onTextChanged.
@@ -306,15 +317,19 @@ import java.util.ArrayList;
    public void onEditorAction(int actionCode) {
        switch (actionCode) {
        case EditorInfo.IME_ACTION_NEXT:
            // Since the cursor will no longer be in the same place as the
            // focus, set the focus controller back to inactive
            mWebView.setFocusControllerInactive();
            mWebView.nativeMoveCursorToNextTextInput();
            mOkayForFocusNotToMatch = true;
            // Pass the click to set the focus to the textfield which will now
            // have the cursor.
            mWebView.centerKeyPressOnTextField();
            // Preemptively rebuild the WebTextView, so that the action will
            // be set properly.
            mWebView.rebuildWebTextView();
            // Since the cursor will no longer be in the same place as the
            // focus, set the focus controller back to inactive
            mWebView.setFocusControllerInactive();
            setDefaultSelection();
            mWebView.invalidate();
            mOkayForFocusNotToMatch = true;
            break;
        case EditorInfo.IME_ACTION_DONE:
            super.onEditorAction(actionCode);
@@ -333,6 +348,14 @@ import java.util.ArrayList;
        }
    }

    @Override
    protected void onFocusChanged(boolean focused, int direction,
            Rect previouslyFocusedRect) {
        mFromFocusChange = true;
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
        mFromFocusChange = false;
    }

    @Override
    protected void onSelectionChanged(int selStart, int selEnd) {
        // This code is copied from TextView.onDraw().  That code does not get
@@ -345,7 +368,8 @@ import java.util.ArrayList;
            int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
            imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
        }
        if (!mFromWebKit && mWebView != null) {
        if (!mFromWebKit && !mFromFocusChange && !mFromSetInputType
                && mWebView != null) {
            if (DebugFlags.WEB_TEXT_VIEW) {
                Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
                        + " selEnd=" + selEnd);
@@ -593,6 +617,17 @@ import java.util.ArrayList;
        }
    }

    /**
     * Sets the selection when the user clicks on a textfield or textarea with
     * the trackball or center key, or starts typing into it without clicking on
     * it.
     */
    /* package */ void setDefaultSelection() {
        Spannable text = (Spannable) getText();
        int selection = mSingle ? text.length() : 0;
        Selection. setSelection(text, selection, selection);
    }

    /**
     * Determine whether to use the system-wide password disguising method,
     * or to use none.
@@ -663,6 +698,13 @@ import java.util.ArrayList;
        setTextColor(Color.BLACK);
    }

    @Override
    public void setInputType(int type) {
        mFromSetInputType = true;
        super.setInputType(type);
        mFromSetInputType = false;
    }

    /* package */ void setMaxLength(int maxLength) {
        mMaxLength = maxLength;
        if (-1 == maxLength) {
@@ -763,32 +805,6 @@ import java.util.ArrayList;
        setInputType(inputType);
    }

    /**
     * Set the text for this WebTextView, and set the selection to (start, end)
     * @param   text    Text to go into this WebTextView.
     * @param   start   Beginning of the selection.
     * @param   end     End of the selection.
     */
    /* package */ void setText(CharSequence text, int start, int end) {
        mPreChange = text.toString();
        setText(text);
        Spannable span = (Spannable) getText();
        int length = span.length();
        if (end > length) {
            end = length;
        }
        if (start < 0) {
            start = 0;
        } else if (start > length) {
            start = length;
        }
        if (DebugFlags.WEB_TEXT_VIEW) {
            Log.v(LOGTAG, "setText start=" + start
                    + " end=" + end);
        }
        Selection.setSelection(span, start, end);
    }

    /**
     * Set the text to the new string, but use the old selection, making sure
     * to keep it within the new string.
+21 −36
Original line number Diff line number Diff line
@@ -3095,6 +3095,16 @@ public class WebView extends AbsoluteLayout
        imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
    }

    /**
     * Only for calling from JNI.  Allows a click on an unfocused textfield to
     * put the textfield in focus.
     */
    private void setOkayNotToMatch() {
        if (inEditingMode()) {
            mWebTextView.mOkayForFocusNotToMatch = true;
        }
    }

    /*
     * This method checks the current focus and cursor and potentially rebuilds
     * mWebTextView to have the appropriate properties, such as password,
@@ -3150,6 +3160,7 @@ public class WebView extends AbsoluteLayout
                    && nativeTextGeneration() == mTextGeneration) {
                mWebTextView.setTextAndKeepSelection(text);
            } else {
                // FIXME: Determine whether this is necessary.
                Selection.setSelection(spannable, start, end);
            }
        } else {
@@ -3182,34 +3193,12 @@ public class WebView extends AbsoluteLayout
            mWebTextView.setSingleLine(isTextField);
            mWebTextView.setInPassword(nativeFocusCandidateIsPassword());
            if (null == text) {
                mWebTextView.setText("", 0, 0);
                if (DebugFlags.WEB_VIEW) {
                    Log.v(LOGTAG, "rebuildWebTextView null == text");
                }
            } else {
                // Change to true to enable the old style behavior, where
                // entering a textfield/textarea always set the selection to the
                // whole field.  This was desirable for the case where the user
                // intends to scroll past the field using the trackball.
                // However, it causes a problem when replying to emails - the
                // user expects the cursor to be at the beginning of the
                // textarea.  Testing out a new behavior, where textfields set
                // selection at the end, and textareas at the beginning.
                if (false) {
                    mWebTextView.setText(text, 0, text.length());
                } else if (isTextField) {
                    int length = text.length();
                    mWebTextView.setText(text, length, length);
                    if (DebugFlags.WEB_VIEW) {
                        Log.v(LOGTAG, "rebuildWebTextView length=" + length);
                    }
                } else {
                    mWebTextView.setText(text, 0, 0);
                    if (DebugFlags.WEB_VIEW) {
                        Log.v(LOGTAG, "rebuildWebTextView !isTextField");
                    }
                }
                text = "";
            }
            mWebTextView.setTextAndKeepSelection(text);
            mWebTextView.requestFocus();
        }
    }
@@ -3365,15 +3354,16 @@ public class WebView extends AbsoluteLayout
            rebuildWebTextView();
            // Now we need to pass the event to it
            if (inEditingMode()) {
                mWebTextView.mResendKeyDown = true;
                return mWebTextView.onKeyDown(keyCode, event);
                mWebTextView.setDefaultSelection();
                mWebTextView.mOkayForFocusNotToMatch = true;
                return mWebTextView.dispatchKeyEvent(event);
            }
        } else if (nativeHasFocusNode()) {
            // In this case, the cursor is not on a text input, but the focus
            // might be.  Check it, and if so, hand over to the WebTextView.
            rebuildWebTextView();
            if (inEditingMode()) {
                return mWebTextView.onKeyDown(keyCode, event);
                return mWebTextView.dispatchKeyEvent(event);
            }
        }

@@ -3460,6 +3450,10 @@ public class WebView extends AbsoluteLayout
            if (nativeCursorIsTextInput()) {
                rebuildWebTextView();
                centerKeyPressOnTextField();
                if (inEditingMode()) {
                    mWebTextView.setDefaultSelection();
                    mWebTextView.mOkayForFocusNotToMatch = true;
                }
                return true;
            }
            nativeSetFollowedLink(true);
@@ -4937,15 +4931,6 @@ public class WebView extends AbsoluteLayout
    }

    /* package */ void passToJavaScript(String currentText, KeyEvent event) {
        if (nativeCursorWantsKeyEvents() && !nativeCursorMatchesFocus()) {
            mWebViewCore.sendMessage(EventHub.CLICK);
            if (mWebTextView.mOkayForFocusNotToMatch) {
                int select = nativeFocusCandidateIsTextField() ?
                        nativeFocusCandidateMaxLength() : 0;
                setSelection(select, select);
                mWebTextView.mOkayForFocusNotToMatch = false; // only once
            }
        }
        WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
        arg.mEvent = event;
        arg.mCurrentText = currentText;