Merge "Add back auto-completion and auto-fill."
This commit is contained in:
264
core/java/android/webkit/AutoCompletePopup.java
Normal file
264
core/java/android/webkit/AutoCompletePopup.java
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.webkit;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Handler;
|
||||
import android.os.Message;
|
||||
import android.text.Editable;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.widget.AbsoluteLayout;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.Filter;
|
||||
import android.widget.Filterable;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListPopupWindow;
|
||||
|
||||
class AutoCompletePopup implements OnItemClickListener, Filter.FilterListener {
|
||||
private static class AnchorView extends View {
|
||||
AnchorView(Context context) {
|
||||
super(context);
|
||||
setFocusable(false);
|
||||
}
|
||||
}
|
||||
private static final int AUTOFILL_FORM = 100;
|
||||
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;
|
||||
|
||||
public AutoCompletePopup(Context context,
|
||||
WebViewClassic webView,
|
||||
WebViewClassic.WebViewInputConnection inputConnection) {
|
||||
mInputConnection = inputConnection;
|
||||
mWebView = webView;
|
||||
mPopup = new ListPopupWindow(context);
|
||||
mAnchor = new AnchorView(context);
|
||||
mWebView.getWebView().addView(mAnchor);
|
||||
mPopup.setOnItemClickListener(this);
|
||||
mPopup.setAnchorView(mAnchor);
|
||||
mPopup.setPromptPosition(ListPopupWindow.POSITION_PROMPT_BELOW);
|
||||
mHandler = new Handler() {
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
switch (msg.what) {
|
||||
case AUTOFILL_FORM:
|
||||
mWebView.autoFillForm(mQueryId);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && mPopup.isShowing()) {
|
||||
// special case for the back key, we do not even try to send it
|
||||
// to the drop down list but instead, consume it immediately
|
||||
if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) {
|
||||
KeyEvent.DispatcherState state = mAnchor.getKeyDispatcherState();
|
||||
if (state != null) {
|
||||
state.startTracking(event, this);
|
||||
}
|
||||
return true;
|
||||
} else if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
KeyEvent.DispatcherState state = mAnchor.getKeyDispatcherState();
|
||||
if (state != null) {
|
||||
state.handleUpEvent(event);
|
||||
}
|
||||
if (event.isTracking() && !event.isCanceled()) {
|
||||
Log.v("AutoCompletePopup", "dismiss popup 2");
|
||||
mPopup.dismiss();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mPopup.isShowing()) {
|
||||
return mPopup.onKeyPreIme(keyCode, event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setFocused(boolean isFocused) {
|
||||
mIsFocused = isFocused;
|
||||
if (!mIsFocused) {
|
||||
Log.v("AutoCompletePopup", "dismiss popup 3");
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(CharSequence text) {
|
||||
mText = text;
|
||||
if (mFilter != null) {
|
||||
mFilter.filter(text, this);
|
||||
}
|
||||
}
|
||||
|
||||
public void setAutoFillQueryId(int queryId) {
|
||||
mQueryId = queryId;
|
||||
}
|
||||
|
||||
public void clearAdapter() {
|
||||
mAdapter = null;
|
||||
mFilter = null;
|
||||
Log.v("AutoCompletePopup", "dismiss popup 4");
|
||||
mPopup.dismiss();
|
||||
mPopup.setAdapter(null);
|
||||
}
|
||||
|
||||
public <T extends ListAdapter & Filterable> void setAdapter(T adapter) {
|
||||
mPopup.setAdapter(adapter);
|
||||
mAdapter = adapter;
|
||||
if (adapter != null) {
|
||||
mFilter = adapter.getFilter();
|
||||
mFilter.filter(mText, this);
|
||||
} else {
|
||||
mFilter = null;
|
||||
}
|
||||
resetRect();
|
||||
}
|
||||
|
||||
public void setNodeBounds(Rect nodeBounds, int layerId) {
|
||||
mNodeBounds.set(nodeBounds);
|
||||
mNodeLayerId = layerId;
|
||||
resetRect();
|
||||
}
|
||||
|
||||
public void resetRect() {
|
||||
Log.v("AutoCompletePopup", "resetRect: " + mNodeBounds);
|
||||
int left = mWebView.contentToViewX(mNodeBounds.left);
|
||||
int right = mWebView.contentToViewX(mNodeBounds.right);
|
||||
int width = right - left;
|
||||
mPopup.setWidth(width);
|
||||
|
||||
int bottom = mWebView.contentToViewY(mNodeBounds.bottom);
|
||||
int top = mWebView.contentToViewY(mNodeBounds.top);
|
||||
int height = bottom - top;
|
||||
|
||||
AbsoluteLayout.LayoutParams lp =
|
||||
(AbsoluteLayout.LayoutParams) mAnchor.getLayoutParams();
|
||||
boolean needsUpdate = false;
|
||||
if (null == lp) {
|
||||
lp = new AbsoluteLayout.LayoutParams(width, height, left, top);
|
||||
} else {
|
||||
if ((lp.x != left) || (lp.y != top) || (lp.width != width)
|
||||
|| (lp.height != height)) {
|
||||
needsUpdate = true;
|
||||
lp.x = left;
|
||||
lp.y = top;
|
||||
lp.width = width;
|
||||
lp.height = height;
|
||||
}
|
||||
}
|
||||
Log.v("AutoCompletePopup", "resetRect layout " + lp.x + ", " + lp.y +
|
||||
", " + lp.width + ", " + lp.height);
|
||||
if (needsUpdate) {
|
||||
mAnchor.setLayoutParams(lp);
|
||||
}
|
||||
if (mPopup.isShowing()) {
|
||||
Log.v("AutoCompletePopup", "showing popup again");
|
||||
mPopup.show(); // update its position
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
if (id == 0 && position == 0 && mInputConnection.getIsAutoFillable()) {
|
||||
mText = "";
|
||||
pushTextToInputConnection();
|
||||
// Blank out the text box while we wait for WebCore to fill the form.
|
||||
if (mIsAutoFillProfileSet) {
|
||||
// Call a webview method to tell WebCore to autofill the form.
|
||||
mWebView.autoFillForm(mQueryId);
|
||||
} else {
|
||||
// There is no autofill profile setup yet and the user has
|
||||
// elected to try and set one up. Call through to the
|
||||
// embedder to action that.
|
||||
mWebView.getWebChromeClient().setupAutoFill(
|
||||
mHandler.obtainMessage(AUTOFILL_FORM));
|
||||
}
|
||||
} else {
|
||||
Object selectedItem;
|
||||
if (position < 0) {
|
||||
selectedItem = mPopup.getSelectedItem();
|
||||
} else {
|
||||
selectedItem = mAdapter.getItem(position);
|
||||
}
|
||||
if (selectedItem != null) {
|
||||
setText(mFilter.convertResultToString(selectedItem));
|
||||
pushTextToInputConnection();
|
||||
}
|
||||
}
|
||||
Log.v("AutoCompletePopup", "dismiss popup 5");
|
||||
mPopup.dismiss();
|
||||
}
|
||||
|
||||
public void setIsAutoFillProfileSet(boolean isAutoFillProfileSet) {
|
||||
mIsAutoFillProfileSet = isAutoFillProfileSet;
|
||||
}
|
||||
|
||||
private void pushTextToInputConnection() {
|
||||
Editable oldText = mInputConnection.getEditable();
|
||||
mInputConnection.setSelection(0, oldText.length());
|
||||
mInputConnection.replaceSelection(mText);
|
||||
mInputConnection.setSelection(mText.length(), mText.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilterComplete(int count) {
|
||||
if (!mIsFocused) {
|
||||
Log.v("AutoCompletePopup", "dismiss popup 1");
|
||||
mPopup.dismiss();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean showDropDown = (count > 0) &&
|
||||
(mInputConnection.getIsAutoFillable() || mText.length() > 0);
|
||||
if (showDropDown) {
|
||||
if (!mPopup.isShowing()) {
|
||||
// Make sure the list does not obscure the IME when shown for the first time.
|
||||
mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED);
|
||||
}
|
||||
Log.v("AutoCompletePopup", "showing popup");
|
||||
mPopup.show();
|
||||
mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
|
||||
} else {
|
||||
Log.v("AutoCompletePopup", "dismiss popup");
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,7 +375,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
* InputConnection used for ContentEditable. This captures changes
|
||||
* to the text and sends them either as key strokes or text changes.
|
||||
*/
|
||||
private class WebViewInputConnection extends BaseInputConnection {
|
||||
class WebViewInputConnection extends BaseInputConnection {
|
||||
// Used for mapping characters to keys typed.
|
||||
private KeyCharacterMap mKeyCharacterMap;
|
||||
private boolean mIsKeySentByMe;
|
||||
@@ -383,11 +383,31 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
private int mImeOptions;
|
||||
private String mHint;
|
||||
private int mMaxLength;
|
||||
private boolean mIsAutoFillable;
|
||||
private boolean mIsAutoCompleteEnabled;
|
||||
private String mName;
|
||||
|
||||
public WebViewInputConnection() {
|
||||
super(mWebView, true);
|
||||
}
|
||||
|
||||
public void setAutoFillable(int queryId) {
|
||||
mIsAutoFillable = getSettings().getAutoFillEnabled()
|
||||
&& (queryId != WebTextView.FORM_NOT_AUTOFILLABLE);
|
||||
int variation = mInputType & EditorInfo.TYPE_MASK_VARIATION;
|
||||
if (variation != EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD
|
||||
&& (mIsAutoFillable || mIsAutoCompleteEnabled)) {
|
||||
if (mName != null && mName.length() > 0) {
|
||||
requestFormData(mName, mFieldPointer, mIsAutoFillable,
|
||||
mIsAutoCompleteEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getIsAutoFillable() {
|
||||
return mIsAutoFillable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean sendKeyEvent(KeyEvent event) {
|
||||
// Some IMEs send key events directly using sendKeyEvents.
|
||||
@@ -582,6 +602,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
mInputType = inputType;
|
||||
mImeOptions = imeOptions;
|
||||
mMaxLength = initData.mMaxLength;
|
||||
mIsAutoCompleteEnabled = initData.mIsAutoCompleteEnabled;
|
||||
mName = initData.mName;
|
||||
mAutoCompletePopup.clearAdapter();
|
||||
}
|
||||
|
||||
public void setupEditorInfo(EditorInfo outAttrs) {
|
||||
@@ -629,6 +652,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
REPLACE_TEXT, start, end, text.toString());
|
||||
mPrivateHandler.sendMessage(replaceMessage);
|
||||
}
|
||||
if (mAutoCompletePopup != null) {
|
||||
StringBuilder newText = new StringBuilder();
|
||||
newText.append(editable.subSequence(0, start));
|
||||
newText.append(text);
|
||||
newText.append(editable.subSequence(end, editable.length()));
|
||||
mAutoCompletePopup.setText(newText.toString());
|
||||
}
|
||||
mIsKeySentByMe = false;
|
||||
}
|
||||
|
||||
@@ -795,6 +825,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
WebViewInputConnection mInputConnection = null;
|
||||
private int mFieldPointer;
|
||||
private PastePopupWindow mPasteWindow;
|
||||
AutoCompletePopup mAutoCompletePopup;
|
||||
|
||||
private static class OnTrimMemoryListener implements ComponentCallbacks2 {
|
||||
private static OnTrimMemoryListener sInstance = null;
|
||||
@@ -1104,6 +1135,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
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 DRAG_HELD_MOTIONLESS = 8;
|
||||
private static final int AWAKEN_SCROLL_BARS = 9;
|
||||
private static final int PREVENT_DEFAULT_TIMEOUT = 10;
|
||||
@@ -1156,6 +1188,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
static final int REPLACE_TEXT = 143;
|
||||
static final int CLEAR_CARET_HANDLE = 144;
|
||||
static final int KEY_PRESS = 145;
|
||||
static final int RELOCATE_AUTO_COMPLETE_POPUP = 146;
|
||||
static final int FOCUS_NODE_CHANGED = 147;
|
||||
static final int AUTOFILL_FORM = 148;
|
||||
|
||||
private static final int FIRST_PACKAGE_MSG_ID = SCROLL_TO_MSG_ID;
|
||||
private static final int LAST_PACKAGE_MSG_ID = HIT_TEST_RESULT;
|
||||
@@ -3560,7 +3595,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
@Override
|
||||
public void clearFormData() {
|
||||
checkThread();
|
||||
// TODO: Implement b/6083041
|
||||
if (mAutoCompletePopup != null) {
|
||||
mAutoCompletePopup.clearAdapter();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3861,12 +3898,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
|
||||
private void scrollLayerTo(int x, int y) {
|
||||
if (x == mScrollingLayerRect.left && y == mScrollingLayerRect.top) {
|
||||
int dx = mScrollingLayerRect.left - x;
|
||||
int dy = mScrollingLayerRect.top - y;
|
||||
if (dx == 0 && y == 0) {
|
||||
return;
|
||||
}
|
||||
if (mSelectingText) {
|
||||
int dx = mScrollingLayerRect.left - x;
|
||||
int dy = mScrollingLayerRect.top - y;
|
||||
if (mSelectCursorBaseLayerId == mCurrentScrollingLayerId) {
|
||||
mSelectCursorBase.offset(dx, dy);
|
||||
}
|
||||
@@ -3874,6 +3911,9 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
mSelectCursorExtent.offset(dx, dy);
|
||||
}
|
||||
}
|
||||
if (mAutoCompletePopup != null) {
|
||||
mAutoCompletePopup.scrollDelta(mCurrentScrollingLayerId, dx, dy);
|
||||
}
|
||||
nativeScrollLayer(mCurrentScrollingLayerId, x, y);
|
||||
mScrollingLayerRect.left = x;
|
||||
mScrollingLayerRect.top = y;
|
||||
@@ -4726,6 +4766,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
|
||||
private void onZoomAnimationEnd() {
|
||||
mPrivateHandler.sendEmptyMessage(RELOCATE_AUTO_COMPLETE_POPUP);
|
||||
}
|
||||
|
||||
void onFixedLengthZoomAnimationStart() {
|
||||
@@ -4880,11 +4921,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
|
||||
if (mInputConnection == null) {
|
||||
mInputConnection = new WebViewInputConnection();
|
||||
mAutoCompletePopup = new AutoCompletePopup(mContext, this,
|
||||
mInputConnection);
|
||||
}
|
||||
mInputConnection.setupEditorInfo(outAttrs);
|
||||
return mInputConnection;
|
||||
}
|
||||
|
||||
private void relocateAutoCompletePopup() {
|
||||
if (mAutoCompletePopup != null) {
|
||||
mAutoCompletePopup.resetRect();
|
||||
mAutoCompletePopup.setText(mInputConnection.getEditable());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in response to a message from webkit telling us that the soft
|
||||
* keyboard should be launched.
|
||||
@@ -4915,6 +4965,91 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by AutoCompletePopup to find saved form data associated with the
|
||||
* textfield
|
||||
* @param name Name of the textfield.
|
||||
* @param nodePointer Pointer to the node of the textfield, so it can be
|
||||
* compared to the currently focused textfield when the data is
|
||||
* retrieved.
|
||||
* @param autoFillable true if WebKit has determined this field is part of
|
||||
* a form that can be auto filled.
|
||||
* @param autoComplete true if the attribute "autocomplete" is set to true
|
||||
* on the textfield.
|
||||
*/
|
||||
/* package */ void requestFormData(String name, int nodePointer,
|
||||
boolean autoFillable, boolean autoComplete) {
|
||||
if (mWebViewCore.getSettings().getSaveFormData()) {
|
||||
Message update = mPrivateHandler.obtainMessage(REQUEST_FORM_DATA);
|
||||
update.arg1 = nodePointer;
|
||||
RequestFormData updater = new RequestFormData(name, getUrl(),
|
||||
update, autoFillable, autoComplete);
|
||||
Thread t = new Thread(updater);
|
||||
t.start();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This class requests an Adapter for the AutoCompletePopup which shows past
|
||||
* entries stored in the database. It is a Runnable so that it can be done
|
||||
* in its own thread, without slowing down the UI.
|
||||
*/
|
||||
private class RequestFormData implements Runnable {
|
||||
private String mName;
|
||||
private String mUrl;
|
||||
private Message mUpdateMessage;
|
||||
private boolean mAutoFillable;
|
||||
private boolean mAutoComplete;
|
||||
private WebSettingsClassic mWebSettings;
|
||||
|
||||
public RequestFormData(String name, String url, Message msg,
|
||||
boolean autoFillable, boolean autoComplete) {
|
||||
mName = name;
|
||||
mUrl = WebTextView.urlForAutoCompleteData(url);
|
||||
mUpdateMessage = msg;
|
||||
mAutoFillable = autoFillable;
|
||||
mAutoComplete = autoComplete;
|
||||
mWebSettings = getSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList<String> pastEntries = new ArrayList<String>();
|
||||
|
||||
if (mAutoFillable) {
|
||||
// Note that code inside the adapter click handler in AutoCompletePopup depends
|
||||
// on the AutoFill item being at the top of the drop down list. If you change
|
||||
// the order, make sure to do it there too!
|
||||
if (mWebSettings != null && mWebSettings.getAutoFillProfile() != null) {
|
||||
pastEntries.add(mWebView.getResources().getText(
|
||||
com.android.internal.R.string.autofill_this_form).toString() +
|
||||
" " +
|
||||
mAutoFillData.getPreviewString());
|
||||
mAutoCompletePopup.setIsAutoFillProfileSet(true);
|
||||
} else {
|
||||
// There is no autofill profile set up yet, so add an option that
|
||||
// will invite the user to set their profile up.
|
||||
pastEntries.add(mWebView.getResources().getText(
|
||||
com.android.internal.R.string.setup_autofill).toString());
|
||||
mAutoCompletePopup.setIsAutoFillProfileSet(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mAutoComplete) {
|
||||
pastEntries.addAll(mDatabase.getFormData(mUrl, mName));
|
||||
}
|
||||
|
||||
if (pastEntries.size() > 0) {
|
||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
||||
mContext,
|
||||
com.android.internal.R.layout.web_text_view_dropdown,
|
||||
pastEntries);
|
||||
mUpdateMessage.obj = adapter;
|
||||
mUpdateMessage.sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dump the display tree to "/sdcard/displayTree.txt"
|
||||
*
|
||||
@@ -4990,6 +5125,13 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
|| keyCode == KeyEvent.KEYCODE_NUMPAD_ENTER;
|
||||
}
|
||||
|
||||
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
|
||||
if (mAutoCompletePopup != null) {
|
||||
return mAutoCompletePopup.onKeyPreIme(keyCode, event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(int keyCode, KeyEvent event) {
|
||||
if (DebugFlags.WEB_VIEW) {
|
||||
@@ -5593,6 +5735,7 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
// However, do not update the base layer as that hasn't changed
|
||||
setNewPicture(mLoadedPicture, false);
|
||||
}
|
||||
relocateAutoCompletePopup();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -8020,6 +8163,12 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
break;
|
||||
}
|
||||
case REQUEST_FORM_DATA:
|
||||
if (mFieldPointer == msg.arg1) {
|
||||
ArrayAdapter<String> adapter = (ArrayAdapter<String>)msg.obj;
|
||||
mAutoCompletePopup.setAdapter(adapter);
|
||||
}
|
||||
break;
|
||||
|
||||
case LONG_PRESS_CENTER:
|
||||
// as this is shared by keydown and trackballdown, reset all
|
||||
@@ -8174,6 +8323,11 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
break;
|
||||
|
||||
case FOCUS_NODE_CHANGED:
|
||||
if (mAutoCompletePopup != null) {
|
||||
mAutoCompletePopup.setFocused(msg.arg1 == mFieldPointer);
|
||||
}
|
||||
// fall through to HIT_TEST_RESULT
|
||||
case HIT_TEST_RESULT:
|
||||
WebKitHitTest hit = (WebKitHitTest) msg.obj;
|
||||
mFocusedNode = hit;
|
||||
@@ -8190,11 +8344,20 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
|
||||
case SET_AUTOFILLABLE:
|
||||
mAutoFillData = (WebViewCore.AutoFillData) msg.obj;
|
||||
// TODO: Support (b/6083041)
|
||||
if (mInputConnection != null) {
|
||||
mInputConnection.setAutoFillable(mAutoFillData.getQueryId());
|
||||
mAutoCompletePopup.setAutoFillQueryId(mAutoFillData.getQueryId());
|
||||
}
|
||||
break;
|
||||
|
||||
case AUTOFILL_COMPLETE:
|
||||
// TODO: Support (b/6083041)
|
||||
if (mAutoCompletePopup != null) {
|
||||
ArrayList<String> pastEntries = new ArrayList<String>();
|
||||
mAutoCompletePopup.setAdapter(new ArrayAdapter<String>(
|
||||
mContext,
|
||||
com.android.internal.R.layout.web_text_view_dropdown,
|
||||
pastEntries));
|
||||
}
|
||||
break;
|
||||
|
||||
case COPY_TO_CLIPBOARD:
|
||||
@@ -8208,6 +8371,11 @@ 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());
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -8236,6 +8404,15 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
mWebViewCore.sendMessage(EventHub.KEY_PRESS, msg.arg1);
|
||||
break;
|
||||
|
||||
case RELOCATE_AUTO_COMPLETE_POPUP:
|
||||
relocateAutoCompletePopup();
|
||||
break;
|
||||
|
||||
case AUTOFILL_FORM:
|
||||
mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM,
|
||||
msg.arg1, /* unused */0);
|
||||
break;
|
||||
|
||||
default:
|
||||
super.handleMessage(msg);
|
||||
break;
|
||||
@@ -9019,7 +9196,8 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
}
|
||||
|
||||
/*package*/ void autoFillForm(int autoFillQueryId) {
|
||||
mWebViewCore.sendMessage(EventHub.AUTOFILL_FORM, autoFillQueryId, /* unused */0);
|
||||
mPrivateHandler.obtainMessage(AUTOFILL_FORM, autoFillQueryId, 0)
|
||||
.sendToTarget();
|
||||
}
|
||||
|
||||
/* package */ ViewManager getViewManager() {
|
||||
@@ -9169,4 +9347,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
|
||||
private static native int nativeGetHandleLayerId(int instance, int handle,
|
||||
Rect cursorLocation);
|
||||
private static native boolean nativeIsBaseFirst(int instance);
|
||||
private static native void nativeMapLayerRect(int instance, int layerId,
|
||||
Rect rect);
|
||||
}
|
||||
|
||||
@@ -339,10 +339,10 @@ public final class WebViewCore {
|
||||
/**
|
||||
* Called by JNI when the focus node changed.
|
||||
*/
|
||||
private void focusNodeChanged(WebKitHitTest hitTest) {
|
||||
private void focusNodeChanged(int nodePointer, WebKitHitTest hitTest) {
|
||||
if (mWebView == null) return;
|
||||
mWebView.mPrivateHandler.obtainMessage(WebViewClassic.HIT_TEST_RESULT, hitTest)
|
||||
.sendToTarget();
|
||||
mWebView.mPrivateHandler.obtainMessage(WebViewClassic.FOCUS_NODE_CHANGED,
|
||||
nodePointer, 0, hitTest).sendToTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -953,22 +953,32 @@ public final class WebViewCore {
|
||||
static class TextFieldInitData {
|
||||
public TextFieldInitData(int fieldPointer,
|
||||
String text, int type, boolean isSpellCheckEnabled,
|
||||
boolean isTextFieldNext, String label, int maxLength) {
|
||||
boolean autoComplete, boolean isTextFieldNext,
|
||||
String name, String label, int maxLength,
|
||||
Rect nodeBounds, int nodeLayerId) {
|
||||
mFieldPointer = fieldPointer;
|
||||
mText = text;
|
||||
mType = type;
|
||||
mIsAutoCompleteEnabled = autoComplete;
|
||||
mIsSpellCheckEnabled = isSpellCheckEnabled;
|
||||
mIsTextFieldNext = isTextFieldNext;
|
||||
mName = name;
|
||||
mLabel = label;
|
||||
mMaxLength = maxLength;
|
||||
mNodeBounds = nodeBounds;
|
||||
mNodeLayerId = nodeLayerId;
|
||||
}
|
||||
int mFieldPointer;
|
||||
String mText;
|
||||
int mType;
|
||||
boolean mIsSpellCheckEnabled;
|
||||
boolean mIsTextFieldNext;
|
||||
boolean mIsAutoCompleteEnabled;
|
||||
String mName;
|
||||
String mLabel;
|
||||
int mMaxLength;
|
||||
Rect mNodeBounds;
|
||||
int mNodeLayerId;
|
||||
}
|
||||
|
||||
// mAction of TouchEventData can be MotionEvent.getAction() which uses the
|
||||
@@ -2787,14 +2797,16 @@ public final class WebViewCore {
|
||||
|
||||
// called by JNI
|
||||
private void initEditField(int pointer, String text, int inputType,
|
||||
boolean isSpellCheckEnabled, boolean nextFieldIsText,
|
||||
String label, int start, int end, int selectionPtr, int maxLength) {
|
||||
boolean isSpellCheckEnabled, boolean isAutoCompleteEnabled,
|
||||
boolean nextFieldIsText, String name,
|
||||
String label, int start, int end, int selectionPtr, int maxLength,
|
||||
Rect nodeRect, int nodeLayer) {
|
||||
if (mWebView == null) {
|
||||
return;
|
||||
}
|
||||
TextFieldInitData initData = new TextFieldInitData(pointer,
|
||||
text, inputType, isSpellCheckEnabled, nextFieldIsText, label,
|
||||
maxLength);
|
||||
text, inputType, isSpellCheckEnabled, isAutoCompleteEnabled,
|
||||
nextFieldIsText, name, label, maxLength, nodeRect, nodeLayer);
|
||||
Message.obtain(mWebView.mPrivateHandler,
|
||||
WebViewClassic.INIT_EDIT_FIELD, initData).sendToTarget();
|
||||
Message.obtain(mWebView.mPrivateHandler,
|
||||
|
||||
Reference in New Issue
Block a user