Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2215)

Side by Side Diff: content/public/android/java/src/org/chromium/content/browser/SelectionPopupController.java

Issue 2855353002: Make Paste Popup use selection rect for positioning (Closed)
Patch Set: Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser; 5 package org.chromium.content.browser;
6 6
7 import android.annotation.TargetApi; 7 import android.annotation.TargetApi;
8 import android.app.Activity; 8 import android.app.Activity;
9 import android.app.SearchManager; 9 import android.app.SearchManager;
10 import android.content.ClipData; 10 import android.content.ClipData;
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 // of adding and removing it once we switch to Android O SDK. The show/hide method 86 // of adding and removing it once we switch to Android O SDK. The show/hide method
87 // does not require ordering information. 87 // does not require ordering information.
88 private static final int MENU_ITEM_ORDER_TEXT_PROCESS_START = 100; 88 private static final int MENU_ITEM_ORDER_TEXT_PROCESS_START = 100;
89 89
90 private final Context mContext; 90 private final Context mContext;
91 private final WindowAndroid mWindowAndroid; 91 private final WindowAndroid mWindowAndroid;
92 private final WebContents mWebContents; 92 private final WebContents mWebContents;
93 private final RenderCoordinates mRenderCoordinates; 93 private final RenderCoordinates mRenderCoordinates;
94 private ActionMode.Callback mCallback; 94 private ActionMode.Callback mCallback;
95 95
96 // Selection rectangle in DIP. 96 // Selection rectangle in DIP.
boliu 2017/05/04 20:36:11 no longer in DIP? also it has the Y offset thing
amaralp 2017/05/05 01:14:32 Reverted to it being in DIP
97 private final Rect mSelectionRect = new Rect(); 97 private final Rect mSelectionRect = new Rect();
98 98
99 // Self-repeating task that repeatedly hides the ActionMode. This is 99 // Self-repeating task that repeatedly hides the ActionMode. This is
100 // required because ActionMode only exposes a temporary hide routine. 100 // required because ActionMode only exposes a temporary hide routine.
101 private final Runnable mRepeatingHideRunnable; 101 private final Runnable mRepeatingHideRunnable;
102 102
103 private View mView; 103 private View mView;
104 private ActionMode mActionMode; 104 private ActionMode mActionMode;
105 private MenuDescriptor mActionMenuDescriptor; 105 private MenuDescriptor mActionMenuDescriptor;
106 106
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
261 if (!isActionModeValid()) clearSelection(); 261 if (!isActionModeValid()) clearSelection();
262 } 262 }
263 263
264 @TargetApi(Build.VERSION_CODES.M) 264 @TargetApi(Build.VERSION_CODES.M)
265 private ActionMode startFloatingActionMode() { 265 private ActionMode startFloatingActionMode() {
266 ActionMode actionMode = mView.startActionMode( 266 ActionMode actionMode = mView.startActionMode(
267 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); 267 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING);
268 return actionMode; 268 return actionMode;
269 } 269 }
270 270
271 void createAndShowPastePopup(int x, int y, boolean canSelectAll, boolean can EditRichly) { 271 void createAndShowPastePopup(
272 int left, int top, int right, int bottom, boolean canSelectAll, bool ean canEditRichly) {
272 if (mView.getParent() == null || mView.getVisibility() != View.VISIBLE) { 273 if (mView.getParent() == null || mView.getVisibility() != View.VISIBLE) {
273 return; 274 return;
274 } 275 }
275 276
276 if (!supportsFloatingActionMode() && !canPaste()) return; 277 if (!supportsFloatingActionMode() && !canPaste()) return;
277 destroyPastePopup(); 278 destroyPastePopup();
279 setSelectionRect(left, top, right, bottom);
278 mCanSelectAllForPastePopup = canSelectAll; 280 mCanSelectAllForPastePopup = canSelectAll;
279 mCanEditRichlyForPastePopup = canEditRichly; 281 mCanEditRichlyForPastePopup = canEditRichly;
280 PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() { 282 PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() {
281 @Override 283 @Override
282 public void paste() { 284 public void paste() {
283 mWebContents.paste(); 285 mWebContents.paste();
284 mWebContents.dismissTextHandles(); 286 mWebContents.dismissTextHandles();
285 } 287 }
286 288
287 @Override 289 @Override
(...skipping 22 matching lines...) Expand all
310 return SelectionPopupController.this.canPasteAsPlainText(); 312 return SelectionPopupController.this.canPasteAsPlainText();
311 } 313 }
312 }; 314 };
313 Context windowContext = mWindowAndroid.getContext().get(); 315 Context windowContext = mWindowAndroid.getContext().get();
314 if (windowContext == null) return; 316 if (windowContext == null) return;
315 if (supportsFloatingActionMode()) { 317 if (supportsFloatingActionMode()) {
316 mPastePopupMenu = new FloatingPastePopupMenu(windowContext, mView, d elegate); 318 mPastePopupMenu = new FloatingPastePopupMenu(windowContext, mView, d elegate);
317 } else { 319 } else {
318 mPastePopupMenu = new LegacyPastePopupMenu(windowContext, mView, del egate); 320 mPastePopupMenu = new LegacyPastePopupMenu(windowContext, mView, del egate);
319 } 321 }
320 showPastePopup(x, y); 322 showPastePopup();
321 } 323 }
322 324
323 private void showPastePopup(int x, int y) { 325 private void showPastePopup() {
324 // Coordinates are in DIP.
325 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
326 final int xPix = (int) (x * deviceScale);
327 final int yPix = (int) (y * deviceScale);
328 final float browserControlsShownPix = mRenderCoordinates.getContentOffse tYPix();
329 try { 326 try {
330 mPastePopupMenu.show(xPix, (int) (yPix + browserControlsShownPix)); 327 mPastePopupMenu.show(mSelectionRect);
331 } catch (WindowManager.BadTokenException e) { 328 } catch (WindowManager.BadTokenException e) {
332 } 329 }
333 } 330 }
334 331
335 @Override 332 @Override
336 public boolean supportsFloatingActionMode() { 333 public boolean supportsFloatingActionMode() {
337 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; 334 return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
338 } 335 }
339 336
340 void destroyPastePopup() { 337 void destroyPastePopup() {
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
671 * Called when an ActionMode needs to be positioned on screen, potentially o ccluding view 668 * Called when an ActionMode needs to be positioned on screen, potentially o ccluding view
672 * content. Note this may be called on a per-frame basis. 669 * content. Note this may be called on a per-frame basis.
673 * 670 *
674 * @param mode The ActionMode that requires positioning. 671 * @param mode The ActionMode that requires positioning.
675 * @param view The View that originated the ActionMode, in whose coordinates the Rect should 672 * @param view The View that originated the ActionMode, in whose coordinates the Rect should
676 * be provided. 673 * be provided.
677 * @param outRect The Rect to be populated with the content position. 674 * @param outRect The Rect to be populated with the content position.
678 */ 675 */
679 @Override 676 @Override
680 public void onGetContentRect(ActionMode mode, View view, Rect outRect) { 677 public void onGetContentRect(ActionMode mode, View view, Rect outRect) {
678 outRect.set(mSelectionRect);
679 }
680
681 private void setSelectionRect(int left, int top, int right, int bottom) {
681 float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); 682 float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
682 outRect.set((int) (mSelectionRect.left * deviceScale), 683 mSelectionRect.set((int) (left * deviceScale), (int) (top * deviceScale) ,
683 (int) (mSelectionRect.top * deviceScale), 684 (int) (right * deviceScale), (int) (bottom * deviceScale));
684 (int) (mSelectionRect.right * deviceScale),
685 (int) (mSelectionRect.bottom * deviceScale));
686
687 // The selection coordinates are relative to the content viewport, but w e need 685 // The selection coordinates are relative to the content viewport, but w e need
688 // coordinates relative to the containing View. 686 // coordinates relative to the containing View.
689 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix()); 687 mSelectionRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix() );
690 } 688 }
691 689
692 /** 690 /**
693 * Perform an action that depends on the semantics of the selected text. 691 * Perform an action that depends on the semantics of the selected text.
694 */ 692 */
695 @VisibleForTesting 693 @VisibleForTesting
696 void doAssistAction() { 694 void doAssistAction() {
697 if (mClassificationResult == null || !mClassificationResult.hasNamedActi on()) return; 695 if (mClassificationResult == null || !mClassificationResult.hasNamedActi on()) return;
698 696
699 assert mClassificationResult.onClickListener != null 697 assert mClassificationResult.onClickListener != null
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 } 907 }
910 908
911 void restoreSelectionPopupsIfNecessary() { 909 void restoreSelectionPopupsIfNecessary() {
912 if (mHasSelection && !isActionModeValid()) { 910 if (mHasSelection && !isActionModeValid()) {
913 showActionModeOrClearOnFailure(); 911 showActionModeOrClearOnFailure();
914 } 912 }
915 } 913 }
916 914
917 // All coordinates are in DIP. 915 // All coordinates are in DIP.
918 @CalledByNative 916 @CalledByNative
919 private void onSelectionEvent( 917 private void onSelectionEvent(int eventType, int left, int top, int right, i nt bottom) {
920 int eventType, int xAnchor, int yAnchor, int left, int top, int righ t, int bottom) {
921 // Ensure the provided selection coordinates form a non-empty rect, as r equired by 918 // Ensure the provided selection coordinates form a non-empty rect, as r equired by
922 // the selection action mode. 919 // the selection action mode.
923 if (left == right) ++right; 920 if (left == right) ++right;
924 if (top == bottom) ++bottom; 921 if (top == bottom) ++bottom;
925 switch (eventType) { 922 switch (eventType) {
926 case SelectionEventType.SELECTION_HANDLES_SHOWN: 923 case SelectionEventType.SELECTION_HANDLES_SHOWN:
927 mSelectionRect.set(left, top, right, bottom); 924 setSelectionRect(left, top, right, bottom);
928 mHasSelection = true; 925 mHasSelection = true;
929 mUnselectAllOnDismiss = true; 926 mUnselectAllOnDismiss = true;
930 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) { 927 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) {
931 showActionModeOrClearOnFailure(); 928 showActionModeOrClearOnFailure();
932 } else { 929 } else {
933 // Rely on |mSelectionClient| sending a classification reque st and the request 930 // Rely on |mSelectionClient| sending a classification reque st and the request
934 // always calling onClassified() callback. 931 // always calling onClassified() callback.
935 mPendingShowActionMode = true; 932 mPendingShowActionMode = true;
936 } 933 }
937 break; 934 break;
938 935
939 case SelectionEventType.SELECTION_HANDLES_MOVED: 936 case SelectionEventType.SELECTION_HANDLES_MOVED:
940 mSelectionRect.set(left, top, right, bottom); 937 setSelectionRect(left, top, right, bottom);
941 if (mPendingShowActionMode) { 938 if (mPendingShowActionMode) {
942 showActionModeOrClearOnFailure(); 939 showActionModeOrClearOnFailure();
943 } else { 940 } else {
944 invalidateContentRect(); 941 invalidateContentRect();
945 } 942 }
946 break; 943 break;
947 944
948 case SelectionEventType.SELECTION_HANDLES_CLEARED: 945 case SelectionEventType.SELECTION_HANDLES_CLEARED:
949 mHasSelection = false; 946 mHasSelection = false;
950 mUnselectAllOnDismiss = false; 947 mUnselectAllOnDismiss = false;
951 mSelectionRect.setEmpty(); 948 mSelectionRect.setEmpty();
952 finishActionMode(); 949 finishActionMode();
953 break; 950 break;
954 951
955 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: 952 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
956 hideActionMode(true); 953 hideActionMode(true);
957 break; 954 break;
958 955
959 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: 956 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
960 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) { 957 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) {
961 hideActionMode(false); 958 hideActionMode(false);
962 } 959 }
963 // Otherwise rely on |mSelectionClient| sending a classification request and the 960 // Otherwise rely on |mSelectionClient| sending a classification request and the
964 // request always calling onClassified() callback. 961 // request always calling onClassified() callback.
965 break; 962 break;
966 963
967 case SelectionEventType.INSERTION_HANDLE_SHOWN: 964 case SelectionEventType.INSERTION_HANDLE_SHOWN:
968 mSelectionRect.set(left, top, right, bottom); 965 setSelectionRect(left, top, right, bottom);
969 mIsInsertion = true; 966 mIsInsertion = true;
970 break; 967 break;
971 968
972 case SelectionEventType.INSERTION_HANDLE_MOVED: 969 case SelectionEventType.INSERTION_HANDLE_MOVED:
973 mSelectionRect.set(left, top, right, bottom); 970 setSelectionRect(left, top, right, bottom);
974 if (!mScrollInProgress && isPastePopupShowing()) { 971 if (!mScrollInProgress && isPastePopupShowing()) {
975 showPastePopup(xAnchor, yAnchor); 972 showPastePopup();
976 } else { 973 } else {
977 destroyPastePopup(); 974 destroyPastePopup();
978 } 975 }
979 break; 976 break;
980 977
981 case SelectionEventType.INSERTION_HANDLE_TAPPED: 978 case SelectionEventType.INSERTION_HANDLE_TAPPED:
982 if (mWasPastePopupShowingOnInsertionDragStart) { 979 if (mWasPastePopupShowingOnInsertionDragStart) {
983 destroyPastePopup(); 980 destroyPastePopup();
984 } else { 981 } else {
985 mWebContents.showContextMenuAtPoint(xAnchor, yAnchor); 982 mWebContents.showContextMenuAtPoint(
983 mSelectionRect.centerX(), mSelectionRect.centerY());
boliu 2017/05/04 20:36:11 from the xAnchorPix computation below, seems like
amaralp 2017/05/05 01:14:32 Changed it back to bottom left and css pixel
986 } 984 }
987 mWasPastePopupShowingOnInsertionDragStart = false; 985 mWasPastePopupShowingOnInsertionDragStart = false;
988 break; 986 break;
989 987
990 case SelectionEventType.INSERTION_HANDLE_CLEARED: 988 case SelectionEventType.INSERTION_HANDLE_CLEARED:
991 destroyPastePopup(); 989 destroyPastePopup();
992 mIsInsertion = false; 990 mIsInsertion = false;
993 mSelectionRect.setEmpty(); 991 mSelectionRect.setEmpty();
994 break; 992 break;
995 993
996 case SelectionEventType.INSERTION_HANDLE_DRAG_STARTED: 994 case SelectionEventType.INSERTION_HANDLE_DRAG_STARTED:
997 mWasPastePopupShowingOnInsertionDragStart = isPastePopupShowing( ); 995 mWasPastePopupShowingOnInsertionDragStart = isPastePopupShowing( );
998 destroyPastePopup(); 996 destroyPastePopup();
999 break; 997 break;
1000 998
1001 case SelectionEventType.INSERTION_HANDLE_DRAG_STOPPED: 999 case SelectionEventType.INSERTION_HANDLE_DRAG_STOPPED:
1002 if (mWasPastePopupShowingOnInsertionDragStart) { 1000 if (mWasPastePopupShowingOnInsertionDragStart) {
1003 mWebContents.showContextMenuAtPoint(xAnchor, yAnchor); 1001 mWebContents.showContextMenuAtPoint(
1002 mSelectionRect.centerX(), mSelectionRect.centerY());
1004 } 1003 }
1005 mWasPastePopupShowingOnInsertionDragStart = false; 1004 mWasPastePopupShowingOnInsertionDragStart = false;
1006 break; 1005 break;
1007 1006
1008 default: 1007 default:
1009 assert false : "Invalid selection event type."; 1008 assert false : "Invalid selection event type.";
1010 } 1009 }
1011 1010
1012 if (mSelectionClient != null) { 1011 if (mSelectionClient != null) {
1013 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor(); 1012 final float deviceScale = mRenderCoordinates.getDeviceScaleFactor();
1014 int xAnchorPix = (int) (xAnchor * deviceScale); 1013 int xAnchorPix = (int) (mSelectionRect.left * deviceScale);
boliu 2017/05/04 20:36:11 isn't mSelectionRect already multiplied by scale?
amaralp 2017/05/05 01:14:32 Yeah, made it not be multiplied by scale.
1015 int yAnchorPix = (int) (yAnchor * deviceScale); 1014 int yAnchorPix = (int) (mSelectionRect.bottom * deviceScale);
1016 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ; 1015 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ;
1017 } 1016 }
1018 } 1017 }
1019 1018
1020 /** 1019 /**
1021 * Clears the current text selection. Note that we will try to move cursor t o selection 1020 * Clears the current text selection. Note that we will try to move cursor t o selection
1022 * end if applicable. 1021 * end if applicable.
1023 */ 1022 */
1024 void clearSelection() { 1023 void clearSelection() {
1025 if (mWebContents == null || !isActionModeSupported()) return; 1024 if (mWebContents == null || !isActionModeSupported()) return;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
1134 if (mPendingShowActionMode) return; 1133 if (mPendingShowActionMode) return;
1135 } 1134 }
1136 1135
1137 // Rely on this method to clear |mHidden| and unhide the action mode . 1136 // Rely on this method to clear |mHidden| and unhide the action mode .
1138 showActionModeOrClearOnFailure(); 1137 showActionModeOrClearOnFailure();
1139 } 1138 }
1140 }; 1139 };
1141 1140
1142 private native void nativeInit(WebContents webContents); 1141 private native void nativeInit(WebContents webContents);
1143 } 1142 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698