Chromium Code Reviews| OLD | NEW |
|---|---|
| 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.ClipboardManager; | 10 import android.content.ClipboardManager; |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 109 private String mLastSelectedText; | 109 private String mLastSelectedText; |
| 110 | 110 |
| 111 // Tracks whether a selection is currently active. When applied to selected text, indicates | 111 // Tracks whether a selection is currently active. When applied to selected text, indicates |
| 112 // whether the last selected text is still highlighted. | 112 // whether the last selected text is still highlighted. |
| 113 private boolean mHasSelection; | 113 private boolean mHasSelection; |
| 114 | 114 |
| 115 // Lazily created paste popup menu, triggered either via long press in an | 115 // Lazily created paste popup menu, triggered either via long press in an |
| 116 // editable region or from tapping the insertion handle. | 116 // editable region or from tapping the insertion handle. |
| 117 private PastePopupMenu mPastePopupMenu; | 117 private PastePopupMenu mPastePopupMenu; |
| 118 private boolean mWasPastePopupShowingOnInsertionDragStart; | 118 private boolean mWasPastePopupShowingOnInsertionDragStart; |
| 119 private boolean mSelectionHandleDragStopped; | |
|
aelias_OOO_until_Jul13
2017/04/21 21:42:19
I think it would be clearer to invert this, "mDrag
| |
| 119 | 120 |
| 120 // The client that processes textual selection, or null if none exists. | 121 // The client that processes textual selection, or null if none exists. |
| 121 private SelectionClient mSelectionClient; | 122 private SelectionClient mSelectionClient; |
| 122 | 123 |
| 123 // The classificaton result of the selected text if the selection exists and | 124 // The classificaton result of the selected text if the selection exists and |
| 124 // ContextSelectionProvider was able to classify it, otherwise null. | 125 // ContextSelectionProvider was able to classify it, otherwise null. |
| 125 private ContextSelectionProvider.Result mClassificationResult; | 126 private ContextSelectionProvider.Result mClassificationResult; |
| 126 | 127 |
| 127 // The resource ID for Assist menu item. | 128 // The resource ID for Assist menu item. |
| 128 private int mAssistMenuItemId; | 129 private int mAssistMenuItemId; |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 201 // True if action mode is initialized to a working (not a no-op) mode. | 202 // True if action mode is initialized to a working (not a no-op) mode. |
| 202 private boolean isActionModeSupported() { | 203 private boolean isActionModeSupported() { |
| 203 return mCallback != EMPTY_CALLBACK; | 204 return mCallback != EMPTY_CALLBACK; |
| 204 } | 205 } |
| 205 | 206 |
| 206 @Override | 207 @Override |
| 207 public void setAllowedMenuItems(int allowedMenuItems) { | 208 public void setAllowedMenuItems(int allowedMenuItems) { |
| 208 mAllowedMenuItems = allowedMenuItems; | 209 mAllowedMenuItems = allowedMenuItems; |
| 209 } | 210 } |
| 210 | 211 |
| 212 public void showSelectionMenu(int xAnchor, int yAnchor, int left, int top, i nt right, | |
| 213 int bottom, boolean isEditable, boolean isPasswordType, String selec tionText, | |
| 214 boolean canSelectAll) { | |
| 215 mSelectionRect.set(left, top, right, bottom); | |
| 216 mEditable = isEditable; | |
| 217 mLastSelectedText = selectionText; | |
| 218 mIsPasswordType = isPasswordType; | |
| 219 mHasSelection = selectionText.length() != 0; | |
|
aelias_OOO_until_Jul13
2017/04/21 21:42:19
This state is redundant now, can be replaced by bo
| |
| 220 mIsInsertion = selectionText.length() == 0; | |
|
aelias_OOO_until_Jul13
2017/04/21 21:42:19
Likewise for mIsInsertion maybe? Is there any val
| |
| 221 mCanSelectAllForPastePopup = canSelectAll; | |
| 222 mUnselectAllOnDismiss = true; | |
| 223 if (isInsertion()) { | |
| 224 createAndShowPastePopup(xAnchor, yAnchor); | |
| 225 } else { | |
| 226 if (mSelectionClient == null | |
| 227 || !mSelectionClient.sendsSelectionPopupUpdates(!mSelectionH andleDragStopped)) { | |
| 228 showActionModeOrClearOnFailure(); | |
| 229 } else { | |
| 230 // Rely on |mSelectionClient| sending a classification request a nd the request | |
| 231 // always calling onClassified() callback. | |
| 232 mPendingShowActionMode = true; | |
| 233 } | |
| 234 mSelectionHandleDragStopped = false; | |
| 235 } | |
| 236 } | |
| 237 | |
| 211 /** | 238 /** |
| 212 * Show (activate) android action mode by starting it. | 239 * Show (activate) android action mode by starting it. |
| 213 * | 240 * |
| 214 * <p>Action mode in floating mode is tried first, and then falls back to | 241 * <p>Action mode in floating mode is tried first, and then falls back to |
| 215 * a normal one. | 242 * a normal one. |
| 216 * <p> If the action mode cannot be created the selection is cleared. | 243 * <p> If the action mode cannot be created the selection is cleared. |
| 217 */ | 244 */ |
| 218 public void showActionModeOrClearOnFailure() { | 245 public void showActionModeOrClearOnFailure() { |
| 219 mPendingShowActionMode = false; | 246 mPendingShowActionMode = false; |
| 220 | 247 |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 246 if (!isActionModeValid()) clearSelection(); | 273 if (!isActionModeValid()) clearSelection(); |
| 247 } | 274 } |
| 248 | 275 |
| 249 @TargetApi(Build.VERSION_CODES.M) | 276 @TargetApi(Build.VERSION_CODES.M) |
| 250 private ActionMode startFloatingActionMode() { | 277 private ActionMode startFloatingActionMode() { |
| 251 ActionMode actionMode = mView.startActionMode( | 278 ActionMode actionMode = mView.startActionMode( |
| 252 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); | 279 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); |
| 253 return actionMode; | 280 return actionMode; |
| 254 } | 281 } |
| 255 | 282 |
| 256 void createAndShowPastePopup(int x, int y, boolean canSelectAll) { | 283 void createAndShowPastePopup(int x, int y) { |
| 257 if (mView.getParent() == null || mView.getVisibility() != View.VISIBLE) { | 284 if (mView.getParent() == null || mView.getVisibility() != View.VISIBLE) { |
| 258 return; | 285 return; |
| 259 } | 286 } |
| 260 | 287 |
| 261 if (!supportsFloatingActionMode() && !canPaste()) return; | 288 if (!supportsFloatingActionMode() && !canPaste()) return; |
| 262 destroyPastePopup(); | 289 destroyPastePopup(); |
| 263 mCanSelectAllForPastePopup = canSelectAll; | |
| 264 PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() { | 290 PastePopupMenuDelegate delegate = new PastePopupMenuDelegate() { |
| 265 @Override | 291 @Override |
| 266 public void paste() { | 292 public void paste() { |
| 267 mWebContents.paste(); | 293 mWebContents.paste(); |
| 268 mWebContents.dismissTextHandles(); | 294 mWebContents.dismissTextHandles(); |
| 269 } | 295 } |
| 270 | 296 |
| 271 @Override | 297 @Override |
| 272 public boolean canPaste() { | 298 public boolean canPaste() { |
| 273 return SelectionPopupController.this.canPaste(); | 299 return SelectionPopupController.this.canPaste(); |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 638 } | 664 } |
| 639 } | 665 } |
| 640 | 666 |
| 641 /** | 667 /** |
| 642 * Perform a select all action. | 668 * Perform a select all action. |
| 643 */ | 669 */ |
| 644 @VisibleForTesting | 670 @VisibleForTesting |
| 645 void selectAll() { | 671 void selectAll() { |
| 646 mWebContents.selectAll(); | 672 mWebContents.selectAll(); |
| 647 mClassificationResult = null; | 673 mClassificationResult = null; |
| 648 if (needsActionMenuUpdate()) showActionModeOrClearOnFailure(); | |
| 649 | |
| 650 // Even though the above statement logged a SelectAll user action, we wa nt to | 674 // Even though the above statement logged a SelectAll user action, we wa nt to |
| 651 // track whether the focus was in an editable field, so log that too. | 675 // track whether the focus was in an editable field, so log that too. |
| 652 if (isSelectionEditable()) { | 676 if (isSelectionEditable()) { |
| 653 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); | 677 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); |
| 654 } else { | 678 } else { |
| 655 RecordUserAction.record("MobileActionMode.SelectAllWasNonEditable"); | 679 RecordUserAction.record("MobileActionMode.SelectAllWasNonEditable"); |
| 656 } | 680 } |
| 657 } | 681 } |
| 658 | 682 |
| 659 /** | 683 /** |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 834 // All coordinates are in DIP. | 858 // All coordinates are in DIP. |
| 835 void onSelectionEvent(int eventType, int xAnchor, int yAnchor, | 859 void onSelectionEvent(int eventType, int xAnchor, int yAnchor, |
| 836 int left, int top, int right, int bottom, boolean isScrollInProgress , | 860 int left, int top, int right, int bottom, boolean isScrollInProgress , |
| 837 boolean touchScrollInProgress) { | 861 boolean touchScrollInProgress) { |
| 838 // Ensure the provided selection coordinates form a non-empty rect, as r equired by | 862 // Ensure the provided selection coordinates form a non-empty rect, as r equired by |
| 839 // the selection action mode. | 863 // the selection action mode. |
| 840 if (left == right) ++right; | 864 if (left == right) ++right; |
| 841 if (top == bottom) ++bottom; | 865 if (top == bottom) ++bottom; |
| 842 switch (eventType) { | 866 switch (eventType) { |
| 843 case SelectionEventType.SELECTION_HANDLES_SHOWN: | 867 case SelectionEventType.SELECTION_HANDLES_SHOWN: |
| 844 mSelectionRect.set(left, top, right, bottom); | |
| 845 mHasSelection = true; | |
| 846 mUnselectAllOnDismiss = true; | |
| 847 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) { | |
| 848 showActionModeOrClearOnFailure(); | |
| 849 } else { | |
| 850 // Rely on |mSelectionClient| sending a classification reque st and the request | |
| 851 // always calling onClassified() callback. | |
| 852 mPendingShowActionMode = true; | |
| 853 } | |
| 854 break; | 868 break; |
| 855 | 869 |
| 856 case SelectionEventType.SELECTION_HANDLES_MOVED: | 870 case SelectionEventType.SELECTION_HANDLES_MOVED: |
| 857 mSelectionRect.set(left, top, right, bottom); | 871 mSelectionRect.set(left, top, right, bottom); |
| 858 if (mPendingShowActionMode) { | 872 if (mPendingShowActionMode) { |
| 859 showActionModeOrClearOnFailure(); | 873 showActionModeOrClearOnFailure(); |
| 860 } else { | 874 } else { |
| 861 invalidateContentRect(); | 875 invalidateContentRect(); |
| 862 } | 876 } |
| 863 break; | 877 break; |
| 864 | 878 |
| 865 case SelectionEventType.SELECTION_HANDLES_CLEARED: | 879 case SelectionEventType.SELECTION_HANDLES_CLEARED: |
| 866 mHasSelection = false; | 880 mHasSelection = false; |
| 867 mUnselectAllOnDismiss = false; | 881 mUnselectAllOnDismiss = false; |
| 868 mSelectionRect.setEmpty(); | 882 mSelectionRect.setEmpty(); |
| 869 finishActionMode(); | 883 finishActionMode(); |
| 870 break; | 884 break; |
| 871 | 885 |
| 872 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: | 886 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: |
| 887 mSelectionHandleDragStopped = false; | |
| 873 hideActionMode(true); | 888 hideActionMode(true); |
| 874 break; | 889 break; |
| 875 | 890 |
| 876 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: | 891 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: |
| 877 if (mSelectionClient == null || !mSelectionClient.sendsSelection PopupUpdates()) { | 892 mSelectionHandleDragStopped = true; |
| 878 hideActionMode(false); | 893 mWebContents.showContextMenuAtPoint(xAnchor, yAnchor); |
| 879 } | |
| 880 // Otherwise rely on |mSelectionClient| sending a classification request and the | |
| 881 // request always calling onClassified() callback. | |
| 882 break; | 894 break; |
| 883 | 895 |
| 884 case SelectionEventType.INSERTION_HANDLE_SHOWN: | 896 case SelectionEventType.INSERTION_HANDLE_SHOWN: |
| 885 mSelectionRect.set(left, top, right, bottom); | 897 mSelectionRect.set(left, top, right, bottom); |
| 886 mIsInsertion = true; | 898 mIsInsertion = true; |
| 887 break; | 899 break; |
| 888 | 900 |
| 889 case SelectionEventType.INSERTION_HANDLE_MOVED: | 901 case SelectionEventType.INSERTION_HANDLE_MOVED: |
| 890 mSelectionRect.set(left, top, right, bottom); | 902 mSelectionRect.set(left, top, right, bottom); |
| 891 if (!isScrollInProgress && isPastePopupShowing()) { | 903 if (!isScrollInProgress && isPastePopupShowing()) { |
| (...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1036 | 1048 |
| 1037 // Remain pending until SELECTION_HANDLES_MOVED arrives. | 1049 // Remain pending until SELECTION_HANDLES_MOVED arrives. |
| 1038 if (mPendingShowActionMode) return; | 1050 if (mPendingShowActionMode) return; |
| 1039 } | 1051 } |
| 1040 | 1052 |
| 1041 // Rely on this method to clear |mHidden| and unhide the action mode . | 1053 // Rely on this method to clear |mHidden| and unhide the action mode . |
| 1042 showActionModeOrClearOnFailure(); | 1054 showActionModeOrClearOnFailure(); |
| 1043 } | 1055 } |
| 1044 }; | 1056 }; |
| 1045 } | 1057 } |
| OLD | NEW |