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.
diff --git a/core/java/android/webkit/WebTextView.java b/core/java/android/webkit/WebTextView.java
index 4fafb65..71b1f9f 100644
--- a/core/java/android/webkit/WebTextView.java
+++ b/core/java/android/webkit/WebTextView.java
@@ -84,14 +84,24 @@
     // 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,22 +147,23 @@
                 isArrowKey = true;
                 break;
         }
-        if (!isArrowKey && !mOkayForFocusNotToMatch && !mResendKeyDown
-                && mWebView.nativeFocusNodePointer() != mNodePointer) {
-            if (mWebView.nativeFocusNodePointer() != 0) {
+
+        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.
+                mWebView.removeView(this);
+                mWebView.requestFocus();
+                return mWebView.dispatchKeyEvent(event);
             }
-            // Do not call remove() here, which hides the soft keyboard.  If
-            // the soft keyboard is being displayed, the user will still want
-            // it there.
-            mWebView.removeView(this);
-            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 @@
     public void onEditorAction(int actionCode) {
         switch (actionCode) {
         case EditorInfo.IME_ACTION_NEXT:
-            mWebView.nativeMoveCursorToNextTextInput();
-            // 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();
-            mWebView.invalidate();
+            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();
+            setDefaultSelection();
+            mWebView.invalidate();
             break;
         case EditorInfo.IME_ACTION_DONE:
             super.onEditorAction(actionCode);
@@ -334,6 +349,14 @@
     }
 
     @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
         // executed, however, because the WebTextView does not draw, allowing
@@ -345,7 +368,8 @@
             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);
@@ -594,6 +618,17 @@
     }
 
     /**
+     * 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.
      * @param   inPassword  True if the textfield is a password field.
@@ -663,6 +698,13 @@
         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) {
@@ -764,32 +806,6 @@
     }
 
     /**
-     * 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.
      * @param   text    The new text to place in the textfield.
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 38684df..304c927 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -3095,6 +3095,16 @@
         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 @@
                     && nativeTextGeneration() == mTextGeneration) {
                 mWebTextView.setTextAndKeepSelection(text);
             } else {
+                // FIXME: Determine whether this is necessary.
                 Selection.setSelection(spannable, start, end);
             }
         } else {
@@ -3182,34 +3193,12 @@
             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 @@
             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 @@
             if (nativeCursorIsTextInput()) {
                 rebuildWebTextView();
                 centerKeyPressOnTextField();
+                if (inEditingMode()) {
+                    mWebTextView.setDefaultSelection();
+                    mWebTextView.mOkayForFocusNotToMatch = true;
+                }
                 return true;
             }
             nativeSetFollowedLink(true);
@@ -4937,15 +4931,6 @@
     }
 
     /* 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;