Skip to content

Commit cbd01c3

Browse files
George MountAndroid (Google) Code Review
authored andcommitted
Merge "Paste window instead of action bar when cursor shown."
2 parents fd400f5 + 1023aa4 commit cbd01c3

File tree

1 file changed

+125
-15
lines changed

1 file changed

+125
-15
lines changed

core/java/android/webkit/WebView.java

Lines changed: 125 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import android.text.Selection;
6969
import android.text.TextUtils;
7070
import android.util.AttributeSet;
71+
import android.util.DisplayMetrics;
7172
import android.util.EventLog;
7273
import android.util.Log;
7374
import android.view.Display;
@@ -111,6 +112,8 @@
111112
import android.widget.LinearLayout;
112113
import android.widget.ListView;
113114
import android.widget.OverScroller;
115+
import android.widget.PopupWindow;
116+
import android.widget.TextView;
114117
import android.widget.Toast;
115118

116119
import junit.framework.Assert;
@@ -122,7 +125,6 @@
122125
import java.io.IOException;
123126
import java.io.InputStream;
124127
import java.io.OutputStream;
125-
import java.io.UnsupportedEncodingException;
126128
import java.net.URLDecoder;
127129
import java.util.ArrayList;
128130
import java.util.HashMap;
@@ -423,6 +425,23 @@ public void setTextAndKeepSelection(CharSequence text) {
423425
setSelection(selectionStart, selectionEnd);
424426
}
425427

428+
public void replaceSelection(CharSequence text) {
429+
Editable editable = getEditable();
430+
int selectionStart = Selection.getSelectionStart(editable);
431+
int selectionEnd = Selection.getSelectionEnd(editable);
432+
setNewText(selectionStart, selectionEnd, text);
433+
editable.replace(selectionStart, selectionEnd, text);
434+
InputMethodManager imm = InputMethodManager.peekInstance();
435+
if (imm != null) {
436+
// Since the text has changed, do not allow the IME to replace the
437+
// existing text as though it were a completion.
438+
imm.restartInput(WebView.this);
439+
}
440+
// Move caret to the end of the new text
441+
int newCaret = selectionStart + text.length();
442+
setSelection(newCaret, newCaret);
443+
}
444+
426445
@Override
427446
public boolean setComposingText(CharSequence text, int newCursorPosition) {
428447
Editable editable = getEditable();
@@ -609,6 +628,78 @@ private void sendDeleteKey() {
609628
}
610629
}
611630

631+
private class PastePopupWindow extends PopupWindow implements OnClickListener {
632+
private ViewGroup mContentView;
633+
private TextView mPasteTextView;
634+
635+
public PastePopupWindow() {
636+
super(WebView.this.mContext, null,
637+
com.android.internal.R.attr.textSelectHandleWindowStyle);
638+
setClippingEnabled(true);
639+
LinearLayout linearLayout = new LinearLayout(WebView.this.getContext());
640+
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
641+
mContentView = linearLayout;
642+
mContentView.setBackgroundResource(
643+
com.android.internal.R.drawable.text_edit_paste_window);
644+
645+
LayoutInflater inflater = (LayoutInflater)WebView.this.mContext.
646+
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
647+
648+
ViewGroup.LayoutParams wrapContent = new ViewGroup.LayoutParams(
649+
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
650+
651+
mPasteTextView = (TextView) inflater.inflate(
652+
com.android.internal.R.layout.text_edit_action_popup_text, null);
653+
mPasteTextView.setLayoutParams(wrapContent);
654+
mContentView.addView(mPasteTextView);
655+
mPasteTextView.setText(com.android.internal.R.string.paste);
656+
mPasteTextView.setOnClickListener(this);
657+
this.setContentView(mContentView);
658+
}
659+
660+
public void show(Rect cursorRect, int windowLeft, int windowTop) {
661+
measureContent();
662+
663+
int width = mContentView.getMeasuredWidth();
664+
int height = mContentView.getMeasuredHeight();
665+
int y = cursorRect.top - height;
666+
if (y < windowTop) {
667+
// There's not enough room vertically, move it below the
668+
// handle.
669+
// The selection handle is vertically offset by 1/4 of the
670+
// line height.
671+
y = cursorRect.bottom - (cursorRect.height() / 4) +
672+
mSelectHandleCenter.getIntrinsicHeight();
673+
}
674+
int x = cursorRect.centerX() - (width / 2);
675+
if (x < windowLeft) {
676+
x = windowLeft;
677+
}
678+
if (!isShowing()) {
679+
showAtLocation(WebView.this, Gravity.NO_GRAVITY, x, y);
680+
}
681+
update(x, y, width, height);
682+
}
683+
684+
public void hide() {
685+
dismiss();
686+
}
687+
688+
@Override
689+
public void onClick(View view) {
690+
pasteFromClipboard();
691+
selectionDone();
692+
}
693+
694+
protected void measureContent() {
695+
final DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
696+
mContentView.measure(
697+
View.MeasureSpec.makeMeasureSpec(displayMetrics.widthPixels,
698+
View.MeasureSpec.AT_MOST),
699+
View.MeasureSpec.makeMeasureSpec(displayMetrics.heightPixels,
700+
View.MeasureSpec.AT_MOST));
701+
}
702+
}
612703

613704
// The listener to capture global layout change event.
614705
private InnerGlobalLayoutListener mGlobalLayoutListener = null;
@@ -636,6 +727,7 @@ private void sendDeleteKey() {
636727
private boolean mGLViewportEmpty = false;
637728
WebViewInputConnection mInputConnection = null;
638729
private int mFieldPointer;
730+
private PastePopupWindow mPasteWindow;
639731

640732
/**
641733
* Transportation object for returning WebView across thread boundaries.
@@ -5910,6 +6002,27 @@ private boolean startSelectActionMode() {
59106002
return true;
59116003
}
59126004

6005+
private void showPasteWindow() {
6006+
ClipboardManager cm = (ClipboardManager)(mContext
6007+
.getSystemService(Context.CLIPBOARD_SERVICE));
6008+
if (cm.hasPrimaryClip()) {
6009+
Rect cursorRect = contentToViewRect(mSelectCursorBase);
6010+
int[] location = new int[2];
6011+
getLocationInWindow(location);
6012+
cursorRect.offset(location[0] - mScrollX, location[1] - mScrollY);
6013+
if (mPasteWindow == null) {
6014+
mPasteWindow = new PastePopupWindow();
6015+
}
6016+
mPasteWindow.show(cursorRect, location[0], location[1]);
6017+
}
6018+
}
6019+
6020+
private void hidePasteButton() {
6021+
if (mPasteWindow != null) {
6022+
mPasteWindow.hide();
6023+
}
6024+
}
6025+
59136026
private void syncSelectionCursors() {
59146027
mSelectCursorBaseLayerId =
59156028
nativeGetHandleLayerId(mNativeClass, HANDLE_ID_BASE, mSelectCursorBase);
@@ -5919,13 +6032,11 @@ private void syncSelectionCursors() {
59196032

59206033
private boolean setupWebkitSelect() {
59216034
syncSelectionCursors();
5922-
ClipboardManager cm = (ClipboardManager)(mContext
5923-
.getSystemService(Context.CLIPBOARD_SERVICE));
5924-
if (!mIsCaretSelection || cm.hasPrimaryClip()) {
5925-
if (!startSelectActionMode()) {
5926-
selectionDone();
5927-
return false;
5928-
}
6035+
if (mIsCaretSelection) {
6036+
showPasteWindow();
6037+
} else if (!startSelectActionMode()) {
6038+
selectionDone();
6039+
return false;
59296040
}
59306041
mSelectingText = true;
59316042
mTouchMode = TOUCH_DRAG_MODE;
@@ -5982,6 +6093,7 @@ public void selectAll() {
59826093
*/
59836094
void selectionDone() {
59846095
if (mSelectingText) {
6096+
hidePasteButton();
59856097
mSelectingText = false;
59866098
// finish is idempotent, so this is fine even if selectionDone was
59876099
// called by mSelectCallback.onDestroyActionMode
@@ -6051,12 +6163,8 @@ public void pasteFromClipboard() {
60516163
if (clipData != null) {
60526164
ClipData.Item clipItem = clipData.getItemAt(0);
60536165
CharSequence pasteText = clipItem.getText();
6054-
if (pasteText != null) {
6055-
int[] handles = new int[4];
6056-
getSelectionHandles(handles);
6057-
mWebViewCore.sendMessage(EventHub.DELETE_TEXT, handles);
6058-
mWebViewCore.sendMessage(EventHub.INSERT_TEXT,
6059-
pasteText.toString());
6166+
if (mInputConnection != null) {
6167+
mInputConnection.replaceSelection(pasteText);
60606168
}
60616169
}
60626170
}
@@ -6614,6 +6722,7 @@ public void run() {
66146722
mSelectionStarted = true;
66156723
mSelectDraggingCursor = mSelectCursorBase;
66166724
mPrivateHandler.removeMessages(CLEAR_CARET_HANDLE);
6725+
hidePasteButton();
66176726
} else if (mSelectHandleLeft != null
66186727
&& mSelectHandleLeft.getBounds()
66196728
.contains(shiftedX, shiftedY)) {
@@ -7276,10 +7385,11 @@ private void stopTouch() {
72767385

72777386
if (mSelectingText) {
72787387
mSelectionStarted = false;
7388+
syncSelectionCursors();
72797389
if (mIsCaretSelection) {
72807390
resetCaretTimer();
7391+
showPasteWindow();
72817392
}
7282-
syncSelectionCursors();
72837393
invalidate();
72847394
}
72857395
}

0 commit comments

Comments
 (0)