6868import android .text .Selection ;
6969import android .text .TextUtils ;
7070import android .util .AttributeSet ;
71+ import android .util .DisplayMetrics ;
7172import android .util .EventLog ;
7273import android .util .Log ;
7374import android .view .Display ;
111112import android .widget .LinearLayout ;
112113import android .widget .ListView ;
113114import android .widget .OverScroller ;
115+ import android .widget .PopupWindow ;
116+ import android .widget .TextView ;
114117import android .widget .Toast ;
115118
116119import junit .framework .Assert ;
122125import java .io .IOException ;
123126import java .io .InputStream ;
124127import java .io .OutputStream ;
125- import java .io .UnsupportedEncodingException ;
126128import java .net .URLDecoder ;
127129import java .util .ArrayList ;
128130import 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