am bb107bd6
: Many fixes to text input in the browser, particularly when moving to a new field.
Merge commit 'bb107bd6f7981cd2b2e31a0afc6f6bf2a6d5118f' into eclair-mr2-plus-aosp * commit 'bb107bd6f7981cd2b2e31a0afc6f6bf2a6d5118f': Many fixes to text input in the browser, particularly when moving to a new field.
This commit is contained in:
@ -84,14 +84,24 @@ import java.util.ArrayList;
|
|||||||
// True if the most recent drag event has caused either the TextView to
|
// 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.
|
// scroll or the web page to scroll. Gets reset after a touch down.
|
||||||
private boolean mScrolled;
|
private boolean mScrolled;
|
||||||
// Gets set to true when the the IME jumps to the next textfield. When this
|
// Gets set to true any time the WebTextView has focus, but the navigation
|
||||||
// happens, the next time the user hits a key it is okay for the focus
|
// cache does not yet know that the focus has been changed. This happens
|
||||||
// pointer to not match the WebTextView's node pointer
|
// 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 mOkayForFocusNotToMatch;
|
||||||
boolean mResendKeyDown;
|
|
||||||
// Whether or not a selection change was generated from webkit. If it was,
|
// Whether or not a selection change was generated from webkit. If it was,
|
||||||
// we do not need to pass the selection back to webkit.
|
// we do not need to pass the selection back to webkit.
|
||||||
private boolean mFromWebKit;
|
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 mGotTouchDown;
|
||||||
private boolean mInSetTextAndKeepSelection;
|
private boolean mInSetTextAndKeepSelection;
|
||||||
// Array to store the final character added in onTextChanged, so that its
|
// Array to store the final character added in onTextChanged, so that its
|
||||||
@ -137,22 +147,23 @@ import java.util.ArrayList;
|
|||||||
isArrowKey = true;
|
isArrowKey = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!isArrowKey && !mOkayForFocusNotToMatch && !mResendKeyDown
|
|
||||||
&& mWebView.nativeFocusNodePointer() != mNodePointer) {
|
if (down) {
|
||||||
if (mWebView.nativeFocusNodePointer() != 0) {
|
if (mOkayForFocusNotToMatch) {
|
||||||
|
if (mWebView.nativeFocusNodePointer() == mNodePointer) {
|
||||||
|
mOkayForFocusNotToMatch = false;
|
||||||
|
}
|
||||||
|
} else if (mWebView.nativeFocusNodePointer() != mNodePointer
|
||||||
|
&& !isArrowKey) {
|
||||||
mWebView.nativeClearCursor();
|
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();
|
Spannable text = (Spannable) getText();
|
||||||
int oldLength = text.length();
|
int oldLength = text.length();
|
||||||
// Normally the delete key's dom events are sent via onTextChanged.
|
// Normally the delete key's dom events are sent via onTextChanged.
|
||||||
@ -306,15 +317,19 @@ import java.util.ArrayList;
|
|||||||
public void onEditorAction(int actionCode) {
|
public void onEditorAction(int actionCode) {
|
||||||
switch (actionCode) {
|
switch (actionCode) {
|
||||||
case EditorInfo.IME_ACTION_NEXT:
|
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
|
// Since the cursor will no longer be in the same place as the
|
||||||
// focus, set the focus controller back to inactive
|
// focus, set the focus controller back to inactive
|
||||||
mWebView.setFocusControllerInactive();
|
mWebView.setFocusControllerInactive();
|
||||||
mWebView.invalidate();
|
mWebView.nativeMoveCursorToNextTextInput();
|
||||||
mOkayForFocusNotToMatch = true;
|
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;
|
break;
|
||||||
case EditorInfo.IME_ACTION_DONE:
|
case EditorInfo.IME_ACTION_DONE:
|
||||||
super.onEditorAction(actionCode);
|
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
|
@Override
|
||||||
protected void onSelectionChanged(int selStart, int selEnd) {
|
protected void onSelectionChanged(int selStart, int selEnd) {
|
||||||
// This code is copied from TextView.onDraw(). That code does not get
|
// 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);
|
int candEnd = EditableInputConnection.getComposingSpanEnd(sp);
|
||||||
imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
|
imm.updateSelection(this, selStart, selEnd, candStart, candEnd);
|
||||||
}
|
}
|
||||||
if (!mFromWebKit && mWebView != null) {
|
if (!mFromWebKit && !mFromFocusChange && !mFromSetInputType
|
||||||
|
&& mWebView != null) {
|
||||||
if (DebugFlags.WEB_TEXT_VIEW) {
|
if (DebugFlags.WEB_TEXT_VIEW) {
|
||||||
Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
|
Log.v(LOGTAG, "onSelectionChanged selStart=" + selStart
|
||||||
+ " selEnd=" + selEnd);
|
+ " 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,
|
* Determine whether to use the system-wide password disguising method,
|
||||||
* or to use none.
|
* or to use none.
|
||||||
@ -663,6 +698,13 @@ import java.util.ArrayList;
|
|||||||
setTextColor(Color.BLACK);
|
setTextColor(Color.BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInputType(int type) {
|
||||||
|
mFromSetInputType = true;
|
||||||
|
super.setInputType(type);
|
||||||
|
mFromSetInputType = false;
|
||||||
|
}
|
||||||
|
|
||||||
/* package */ void setMaxLength(int maxLength) {
|
/* package */ void setMaxLength(int maxLength) {
|
||||||
mMaxLength = maxLength;
|
mMaxLength = maxLength;
|
||||||
if (-1 == maxLength) {
|
if (-1 == maxLength) {
|
||||||
@ -763,32 +805,6 @@ import java.util.ArrayList;
|
|||||||
setInputType(inputType);
|
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
|
* Set the text to the new string, but use the old selection, making sure
|
||||||
* to keep it within the new string.
|
* to keep it within the new string.
|
||||||
|
@ -3095,6 +3095,16 @@ public class WebView extends AbsoluteLayout
|
|||||||
imm.hideSoftInputFromWindow(this.getWindowToken(), 0);
|
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
|
* This method checks the current focus and cursor and potentially rebuilds
|
||||||
* mWebTextView to have the appropriate properties, such as password,
|
* mWebTextView to have the appropriate properties, such as password,
|
||||||
@ -3150,6 +3160,7 @@ public class WebView extends AbsoluteLayout
|
|||||||
&& nativeTextGeneration() == mTextGeneration) {
|
&& nativeTextGeneration() == mTextGeneration) {
|
||||||
mWebTextView.setTextAndKeepSelection(text);
|
mWebTextView.setTextAndKeepSelection(text);
|
||||||
} else {
|
} else {
|
||||||
|
// FIXME: Determine whether this is necessary.
|
||||||
Selection.setSelection(spannable, start, end);
|
Selection.setSelection(spannable, start, end);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3182,34 +3193,12 @@ public class WebView extends AbsoluteLayout
|
|||||||
mWebTextView.setSingleLine(isTextField);
|
mWebTextView.setSingleLine(isTextField);
|
||||||
mWebTextView.setInPassword(nativeFocusCandidateIsPassword());
|
mWebTextView.setInPassword(nativeFocusCandidateIsPassword());
|
||||||
if (null == text) {
|
if (null == text) {
|
||||||
mWebTextView.setText("", 0, 0);
|
|
||||||
if (DebugFlags.WEB_VIEW) {
|
if (DebugFlags.WEB_VIEW) {
|
||||||
Log.v(LOGTAG, "rebuildWebTextView null == text");
|
Log.v(LOGTAG, "rebuildWebTextView null == text");
|
||||||
}
|
}
|
||||||
} else {
|
text = "";
|
||||||
// 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
mWebTextView.setTextAndKeepSelection(text);
|
||||||
mWebTextView.requestFocus();
|
mWebTextView.requestFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3365,15 +3354,16 @@ public class WebView extends AbsoluteLayout
|
|||||||
rebuildWebTextView();
|
rebuildWebTextView();
|
||||||
// Now we need to pass the event to it
|
// Now we need to pass the event to it
|
||||||
if (inEditingMode()) {
|
if (inEditingMode()) {
|
||||||
mWebTextView.mResendKeyDown = true;
|
mWebTextView.setDefaultSelection();
|
||||||
return mWebTextView.onKeyDown(keyCode, event);
|
mWebTextView.mOkayForFocusNotToMatch = true;
|
||||||
|
return mWebTextView.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
} else if (nativeHasFocusNode()) {
|
} else if (nativeHasFocusNode()) {
|
||||||
// In this case, the cursor is not on a text input, but the focus
|
// 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.
|
// might be. Check it, and if so, hand over to the WebTextView.
|
||||||
rebuildWebTextView();
|
rebuildWebTextView();
|
||||||
if (inEditingMode()) {
|
if (inEditingMode()) {
|
||||||
return mWebTextView.onKeyDown(keyCode, event);
|
return mWebTextView.dispatchKeyEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3460,6 +3450,10 @@ public class WebView extends AbsoluteLayout
|
|||||||
if (nativeCursorIsTextInput()) {
|
if (nativeCursorIsTextInput()) {
|
||||||
rebuildWebTextView();
|
rebuildWebTextView();
|
||||||
centerKeyPressOnTextField();
|
centerKeyPressOnTextField();
|
||||||
|
if (inEditingMode()) {
|
||||||
|
mWebTextView.setDefaultSelection();
|
||||||
|
mWebTextView.mOkayForFocusNotToMatch = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
nativeSetFollowedLink(true);
|
nativeSetFollowedLink(true);
|
||||||
@ -4937,15 +4931,6 @@ public class WebView extends AbsoluteLayout
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void passToJavaScript(String currentText, KeyEvent event) {
|
/* 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();
|
WebViewCore.JSKeyData arg = new WebViewCore.JSKeyData();
|
||||||
arg.mEvent = event;
|
arg.mEvent = event;
|
||||||
arg.mCurrentText = currentText;
|
arg.mCurrentText = currentText;
|
||||||
|
Reference in New Issue
Block a user