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

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

Issue 2740103006: Implement SmartText selection. (Closed)
Patch Set: Addressed some comments Created 3 years, 9 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.ClipboardManager; 10 import android.content.ClipboardManager;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 * A class that handles input-related web content selection UI like action mode 47 * A class that handles input-related web content selection UI like action mode
48 * and paste popup view. It wraps an {@link ActionMode} created by the associate d view, 48 * and paste popup view. It wraps an {@link ActionMode} created by the associate d view,
49 * providing modified interaction with it. 49 * providing modified interaction with it.
50 * 50 *
51 * Embedders can use {@link ActionModeCallbackHelper} implemented by this class 51 * Embedders can use {@link ActionModeCallbackHelper} implemented by this class
52 * to create {@link ActionMode.Callback} instance and configure the selection ac tion 52 * to create {@link ActionMode.Callback} instance and configure the selection ac tion
53 * mode tasks to their requirements. 53 * mode tasks to their requirements.
54 */ 54 */
55 @TargetApi(Build.VERSION_CODES.M) 55 @TargetApi(Build.VERSION_CODES.M)
56 public class SelectionPopupController extends ActionModeCallbackHelper { 56 public class SelectionPopupController extends ActionModeCallbackHelper {
57 private static final String TAG = "cr.SelectionPopCtlr"; // 20 char limit 57 private static final String TAG = "SelectionPopupCtlr"; // 20 char limit
58 58
59 /** 59 /**
60 * Android Intent size limitations prevent sending over a megabyte of data. Limit 60 * Android Intent size limitations prevent sending over a megabyte of data. Limit
61 * query lengths to 100kB because other things may be added to the Intent. 61 * query lengths to 100kB because other things may be added to the Intent.
62 */ 62 */
63 private static final int MAX_SHARE_QUERY_LENGTH = 100000; 63 private static final int MAX_SHARE_QUERY_LENGTH = 100000;
64 64
65 // Default delay for reshowing the {@link ActionMode} after it has been 65 // Default delay for reshowing the {@link ActionMode} after it has been
66 // hidden. This avoids flickering issues if there are trailing rect 66 // hidden. This avoids flickering issues if there are trailing rect
67 // invalidations after the ActionMode is shown. For example, after the user 67 // invalidations after the ActionMode is shown. For example, after the user
68 // stops dragging a selection handle, in turn showing the ActionMode, the 68 // stops dragging a selection handle, in turn showing the ActionMode, the
69 // selection change response will be asynchronous. 300ms should accomodate 69 // selection change response will be asynchronous. 300ms should accomodate
70 // most such trailing, async delays. 70 // most such trailing, async delays.
71 private static final int SHOW_DELAY_MS = 300; 71 private static final int SHOW_DELAY_MS = 300;
72 72
73 // Display operation for ActionMode (show or invalidate) that is delayed bec ause
74 // the selected text needs to be classified before. See comment to mPostpone dDisplayOp.
75 private static final int POSTPONED_NONE = 0;
76 private static final int POSTPONED_SHOW = 1;
77 private static final int POSTPONED_INVALIDATE = 2;
78
73 private final Context mContext; 79 private final Context mContext;
74 private final WindowAndroid mWindowAndroid; 80 private final WindowAndroid mWindowAndroid;
75 private final WebContents mWebContents; 81 private final WebContents mWebContents;
76 private final RenderCoordinates mRenderCoordinates; 82 private final RenderCoordinates mRenderCoordinates;
77 private final ImeAdapter mImeAdapter; 83 private final ImeAdapter mImeAdapter;
78 private ActionMode.Callback mCallback; 84 private ActionMode.Callback mCallback;
79 85
80 // Selection rectangle in DIP. 86 // Selection rectangle in DIP.
81 private final Rect mSelectionRect = new Rect(); 87 private final Rect mSelectionRect = new Rect();
82 88
(...skipping 25 matching lines...) Expand all
108 private boolean mHasSelection; 114 private boolean mHasSelection;
109 115
110 // Lazily created paste popup menu, triggered either via long press in an 116 // Lazily created paste popup menu, triggered either via long press in an
111 // editable region or from tapping the insertion handle. 117 // editable region or from tapping the insertion handle.
112 private PastePopupMenu mPastePopupMenu; 118 private PastePopupMenu mPastePopupMenu;
113 private boolean mWasPastePopupShowingOnInsertionDragStart; 119 private boolean mWasPastePopupShowingOnInsertionDragStart;
114 120
115 // The client that processes textual selection, or null if none exists. 121 // The client that processes textual selection, or null if none exists.
116 private SelectionClient mSelectionClient; 122 private SelectionClient mSelectionClient;
117 123
124 // The classificaton result of the selected text or null if ContextSelection Provider
125 // could not classify the selection.
boliu 2017/03/20 20:27:26 what's the state of this if there's no selection?
Tima Vaisburd 2017/03/21 02:07:02 Null. I rewrote as "The classificaton result of th
126 private ContextSelectionProvider.Result mClassificationResult;
127
128 // Postponed display operation for ActionMode.
129 // TODO(timav): explain better.
boliu 2017/03/20 20:27:26 later when?
Tima Vaisburd 2017/03/21 02:07:02 Added an explanation.
130 private int mPostponedDisplayOp;
131
132 // The callback object that delivers result from SelectionClient.
133 private ContextSelectionProvider.ResultCallback mSelectonCallback =
amaralp 2017/03/21 02:34:14 Why does this need to be a member of the class? Wh
Tima Vaisburd 2017/03/21 20:50:12 No good reason.
134 new ContextSelectionProvider.ResultCallback() {
135 @Override
136 public void onClassified(ContextSelectionProvider.Result result) {
137 Log.v(TAG, "onClassified");
boliu 2017/03/20 20:27:26 .
Tima Vaisburd 2017/03/21 02:07:02 No more.
138
139 // If the selection does not exist any more, discard |result |.
140 if (!mHasSelection) {
141 mPostponedDisplayOp = POSTPONED_NONE;
142 return;
143 }
144
145 // Update the selection range if needed.
146 if (!(result.startAdjust == 0 && result.endAdjust == 0)) {
147 // This call causes SELECTION_HANDLES_MOVED event
148 mWebContents.adjustSelectionByCharacterOffset(
149 result.startAdjust, result.endAdjust);
150 }
151
152 final boolean hadPriorResult = mClassificationResult != null ;
153 mClassificationResult = result.hasNamedAction() ? result : n ull;
154
155 // For simplicity always update the menu if we need to show assist item.
156 // Also we need to update the menu if the assist item is goi ng to disappear.
157 if (mClassificationResult != null || hadPriorResult) mNeedsP repare = true;
158
159 switch (mPostponedDisplayOp) {
160 case POSTPONED_NONE:
161 break;
162
163 case POSTPONED_SHOW:
164 // TODO(timav): if the |result| contained the select ion adjustment and
amaralp 2017/03/21 02:34:14 One solution for the flickering could be to have t
Tima Vaisburd 2017/03/21 20:50:12 I like that idea although I receive a feedback tha
165 // we called adjustSelectionByCharacterOffset() abov e, there is flicker
166 // if SELECTION_HANDLES_MOVED comes later and invali dates selection
167 // rectangle. Consider postponing till SELECTION_HAN DLES_MOVED or
168 // introduce delay.
169 showActionMode();
170 mPostponedDisplayOp = POSTPONED_NONE;
171 break;
172
173 case POSTPONED_INVALIDATE:
174 invalidateActionMode();
175 mPostponedDisplayOp = POSTPONED_NONE;
176 break;
177
178 default:
179 assert false : "Invalid postponed display operation type.";
180 break;
181 }
182 }
183 };
184
118 /** 185 /**
119 * Create {@link SelectionPopupController} instance. 186 * Create {@link SelectionPopupController} instance.
120 * @param context Context for action mode. 187 * @param context Context for action mode.
121 * @param window WindowAndroid instance. 188 * @param window WindowAndroid instance.
122 * @param webContents WebContents instance. 189 * @param webContents WebContents instance.
123 * @param view Container view. 190 * @param view Container view.
124 * @param renderCoordinates Coordinates info used to position elements. 191 * @param renderCoordinates Coordinates info used to position elements.
125 * @param imeAdapter ImeAdapter instance to handle cursor position. 192 * @param imeAdapter ImeAdapter instance to handle cursor position.
126 */ 193 */
127 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents, 194 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents,
(...skipping 10 matching lines...) Expand all
138 mRepeatingHideRunnable = new Runnable() { 205 mRepeatingHideRunnable = new Runnable() {
139 @Override 206 @Override
140 public void run() { 207 public void run() {
141 assert mHidden; 208 assert mHidden;
142 final long hideDuration = getDefaultHideDuration(); 209 final long hideDuration = getDefaultHideDuration();
143 // Ensure the next hide call occurs before the ActionMode reappe ars. 210 // Ensure the next hide call occurs before the ActionMode reappe ars.
144 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1); 211 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1);
145 hideActionModeTemporarily(hideDuration); 212 hideActionModeTemporarily(hideDuration);
146 } 213 }
147 }; 214 };
215
216 mSelectionClient = ContextSelectionClient.create(mSelectonCallback, wind ow, webContents);
148 } 217 }
149 218
150 /** 219 /**
151 * Update the container view. 220 * Update the container view.
152 */ 221 */
153 void setContainerView(View view) { 222 void setContainerView(View view) {
154 assert view != null; 223 assert view != null;
155 224
156 // Cleans up action mode before switching to a new container view. 225 // Cleans up action mode before switching to a new container view.
157 if (isActionModeValid()) finishActionMode(); 226 if (isActionModeValid()) finishActionMode();
(...skipping 24 matching lines...) Expand all
182 @Override 251 @Override
183 public void setAllowedMenuItems(int allowedMenuItems) { 252 public void setAllowedMenuItems(int allowedMenuItems) {
184 mAllowedMenuItems = allowedMenuItems; 253 mAllowedMenuItems = allowedMenuItems;
185 } 254 }
186 255
187 /** 256 /**
188 * Show (activate) android action mode by starting it. 257 * Show (activate) android action mode by starting it.
189 * 258 *
190 * <p>Action mode in floating mode is tried first, and then falls back to 259 * <p>Action mode in floating mode is tried first, and then falls back to
191 * a normal one. 260 * a normal one.
192 * @return {@code true} if the action mode started successfully or is alread y on. 261 * <p> If the action mode cannot be created the selection is cleared.
193 */ 262 */
194 public boolean showActionMode() { 263 public void showActionMode() {
boliu 2017/03/20 20:27:26 maybe call this showActionModeOrClearOnFailure
Ted C 2017/03/20 20:35:50 Ah, that is why the other code changed.
Tima Vaisburd 2017/03/21 02:07:02 Done.
195 if (isEmpty()) return false; 264 if (isEmpty()) {
265 clearSelection();
266 return;
267 }
196 268
197 // Just refreshes the view if it is already showing. 269 // Just refreshes the view if it is already showing.
198 if (isActionModeValid()) { 270 if (isActionModeValid()) {
199 invalidateActionMode(); 271 invalidateActionMode();
200 return true; 272 return;
201 } 273 }
202 274
203 if (mView.getParent() != null) { 275 if (mView.getParent() != null) {
204 // On ICS, startActionMode throws an NPE when getParent() is null. 276 // On ICS, startActionMode throws an NPE when getParent() is null.
205 assert mWebContents != null; 277 assert mWebContents != null;
206 ActionMode actionMode = supportsFloatingActionMode() 278 ActionMode actionMode = supportsFloatingActionMode()
207 ? startFloatingActionMode() 279 ? startFloatingActionMode()
208 : mView.startActionMode(mCallback); 280 : mView.startActionMode(mCallback);
209 if (actionMode != null) { 281 if (actionMode != null) {
210 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details. 282 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details.
211 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ; 283 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ;
212 } 284 }
213 mActionMode = actionMode; 285 mActionMode = actionMode;
214 } 286 }
215 mUnselectAllOnDismiss = true; 287 mUnselectAllOnDismiss = true;
216 return isActionModeValid(); 288 if (!isActionModeValid()) clearSelection();
217 } 289 }
218 290
219 @TargetApi(Build.VERSION_CODES.M) 291 @TargetApi(Build.VERSION_CODES.M)
220 private ActionMode startFloatingActionMode() { 292 private ActionMode startFloatingActionMode() {
221 ActionMode actionMode = mView.startActionMode( 293 ActionMode actionMode = mView.startActionMode(
222 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); 294 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING);
223 return actionMode; 295 return actionMode;
224 } 296 }
225 297
226 void showPastePopup(int x, int y) { 298 void showPastePopup(int x, int y) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 return mPastePopupMenu != null && mPastePopupMenu.isShowing(); 360 return mPastePopupMenu != null && mPastePopupMenu.isShowing();
289 } 361 }
290 362
291 // Composition methods for android.view.ActionMode 363 // Composition methods for android.view.ActionMode
292 364
293 /** 365 /**
294 * @see ActionMode#finish() 366 * @see ActionMode#finish()
295 */ 367 */
296 @Override 368 @Override
297 public void finishActionMode() { 369 public void finishActionMode() {
370 mPostponedDisplayOp = POSTPONED_NONE;
298 if (isActionModeValid()) { 371 if (isActionModeValid()) {
299 mActionMode.finish(); 372 mActionMode.finish();
300 373
301 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response. 374 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response.
302 mActionMode = null; 375 mActionMode = null;
303 } 376 }
304 } 377 }
305 378
306 /** 379 /**
307 * @see ActionMode#invalidate() 380 * @see ActionMode#invalidate()
308 * Note that invalidation will also reset visibility state. The caller 381 * Note that invalidation will also reset visibility state. The caller
309 * should account for this when making subsequent visibility updates. 382 * should account for this when making subsequent visibility updates.
310 */ 383 */
311 private void invalidateActionMode() { 384 private void invalidateActionMode() {
312 if (!isActionModeValid()) return; 385 if (!isActionModeValid()) return;
313 if (mHidden) { 386 if (mHidden) {
314 assert canHideActionMode(); 387 assert canHideActionMode();
315 mHidden = false; 388 mHidden = false;
316 mView.removeCallbacks(mRepeatingHideRunnable); 389 mView.removeCallbacks(mRepeatingHideRunnable);
390 hideActionModeTemporarily(SHOW_DELAY_MS);
317 mPendingInvalidateContentRect = false; 391 mPendingInvalidateContentRect = false;
318 } 392 }
319 393
320 // Try/catch necessary for framework bug, crbug.com/446717. 394 // Try/catch necessary for framework bug, crbug.com/446717.
321 try { 395 try {
322 mActionMode.invalidate(); 396 mActionMode.invalidate();
323 } catch (NullPointerException e) { 397 } catch (NullPointerException e) {
324 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e); 398 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e);
325 } 399 }
326 } 400 }
327 401
328 /** 402 /**
329 * @see ActionMode#invalidateContentRect() 403 * @see ActionMode#invalidateContentRect()
330 */ 404 */
331 public void invalidateContentRect() { 405 private void invalidateContentRect() {
332 if (supportsFloatingActionMode()) { 406 if (supportsFloatingActionMode()) {
333 if (mHidden) { 407 if (mHidden) {
334 mPendingInvalidateContentRect = true; 408 mPendingInvalidateContentRect = true;
335 } else { 409 } else {
336 mPendingInvalidateContentRect = false; 410 mPendingInvalidateContentRect = false;
337 if (isActionModeValid()) mActionMode.invalidateContentRect(); 411 if (isActionModeValid()) mActionMode.invalidateContentRect();
338 } 412 }
339 } 413 }
340 } 414 }
341 415
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // caused a resource loading failure to be logged. WebView 498 // caused a resource loading failure to be logged. WebView
425 // resource access needs to be improved so that this 499 // resource access needs to be improved so that this
426 // logspam can be avoided. 500 // logspam can be avoided.
427 new MenuInflater(context).inflate(R.menu.select_action_menu, menu); 501 new MenuInflater(context).inflate(R.menu.select_action_menu, menu);
428 } 502 }
429 } 503 }
430 504
431 private void createActionMenu(ActionMode mode, Menu menu) { 505 private void createActionMenu(ActionMode mode, Menu menu) {
432 mNeedsPrepare = false; 506 mNeedsPrepare = false;
433 initializeMenu(mContext, mode, menu); 507 initializeMenu(mContext, mode, menu);
508 updateContextDependantMenuItem(menu);
434 509
435 if (!isSelectionEditable() || !canPaste()) { 510 if (!isSelectionEditable() || !canPaste()) {
436 menu.removeItem(R.id.select_action_menu_paste); 511 menu.removeItem(R.id.select_action_menu_paste);
437 } 512 }
438 513
439 if (isInsertion()) { 514 if (isInsertion()) {
440 menu.removeItem(R.id.select_action_menu_select_all); 515 menu.removeItem(R.id.select_action_menu_select_all);
441 menu.removeItem(R.id.select_action_menu_cut); 516 menu.removeItem(R.id.select_action_menu_cut);
442 menu.removeItem(R.id.select_action_menu_copy); 517 menu.removeItem(R.id.select_action_menu_copy);
443 menu.removeItem(R.id.select_action_menu_share); 518 menu.removeItem(R.id.select_action_menu_share);
(...skipping 22 matching lines...) Expand all
466 541
467 initializeTextProcessingMenu(menu); 542 initializeTextProcessingMenu(menu);
468 } 543 }
469 544
470 private boolean canPaste() { 545 private boolean canPaste() {
471 ClipboardManager clipMgr = (ClipboardManager) 546 ClipboardManager clipMgr = (ClipboardManager)
472 mContext.getSystemService(Context.CLIPBOARD_SERVICE); 547 mContext.getSystemService(Context.CLIPBOARD_SERVICE);
473 return clipMgr.hasPrimaryClip(); 548 return clipMgr.hasPrimaryClip();
474 } 549 }
475 550
551 private void updateContextDependantMenuItem(Menu menu) {
552 Log.v(TAG, "updateContextDependantItem");
boliu 2017/03/20 20:27:26 .
Tima Vaisburd 2017/03/21 02:07:02 Removed. Also s/dependant/dependent/.
553 menu.removeItem(R.id.select_action_menu_context_dep);
554
555 if (mClassificationResult == null) return;
556
557 Log.v(TAG, "updateContextDependantMenuItem: adding item " + mClassificat ionResult.label);
558 menu.add(Menu.NONE, R.id.select_action_menu_context_dep, 1, mClassificat ionResult.label)
559 .setIcon(mClassificationResult.icon)
560 .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
561 }
562
476 /** 563 /**
477 * Intialize the menu items for processing text, if there is any. 564 * Intialize the menu items for processing text, if there is any.
478 */ 565 */
479 private void initializeTextProcessingMenu(Menu menu) { 566 private void initializeTextProcessingMenu(Menu menu) {
480 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M 567 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
481 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) { 568 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) {
482 return; 569 return;
483 } 570 }
484 571
485 PackageManager packageManager = mContext.getPackageManager(); 572 PackageManager packageManager = mContext.getPackageManager();
(...skipping 21 matching lines...) Expand all
507 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame); 594 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame);
508 } 595 }
509 596
510 @Override 597 @Override
511 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 598 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
512 if (!isActionModeValid()) return true; 599 if (!isActionModeValid()) return true;
513 600
514 int id = item.getItemId(); 601 int id = item.getItemId();
515 int groupId = item.getGroupId(); 602 int groupId = item.getGroupId();
516 603
517 if (id == R.id.select_action_menu_select_all) { 604 if (id == R.id.select_action_menu_context_dep) {
605 doContextDependentAction();
606 mode.finish();
607 } else if (id == R.id.select_action_menu_select_all) {
518 selectAll(); 608 selectAll();
519 } else if (id == R.id.select_action_menu_cut) { 609 } else if (id == R.id.select_action_menu_cut) {
520 cut(); 610 cut();
521 mode.finish(); 611 mode.finish();
522 } else if (id == R.id.select_action_menu_copy) { 612 } else if (id == R.id.select_action_menu_copy) {
523 copy(); 613 copy();
524 mode.finish(); 614 mode.finish();
525 } else if (id == R.id.select_action_menu_paste) { 615 } else if (id == R.id.select_action_menu_paste) {
526 paste(); 616 paste();
527 mode.finish(); 617 mode.finish();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 (int) (mSelectionRect.top * deviceScale), 656 (int) (mSelectionRect.top * deviceScale),
567 (int) (mSelectionRect.right * deviceScale), 657 (int) (mSelectionRect.right * deviceScale),
568 (int) (mSelectionRect.bottom * deviceScale)); 658 (int) (mSelectionRect.bottom * deviceScale));
569 659
570 // The selection coordinates are relative to the content viewport, but w e need 660 // The selection coordinates are relative to the content viewport, but w e need
571 // coordinates relative to the containing View. 661 // coordinates relative to the containing View.
572 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix()); 662 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
573 } 663 }
574 664
575 /** 665 /**
666 * Perform an action that depends on the semantics of the selected text.
667 */
668 @VisibleForTesting
669 void doContextDependentAction() {
670 if (mClassificationResult == null) return;
671
672 assert mClassificationResult.onClickListener != null
673 || mClassificationResult.intent != null;
674
675 if (mClassificationResult.onClickListener != null) {
676 mClassificationResult.onClickListener.onClick(mView);
677 return;
678 }
679
680 if (mClassificationResult.intent != null) {
681 Context context = mWindowAndroid.getContext().get();
682 if (context == null) return;
683
684 context.startActivity(mClassificationResult.intent);
685 return;
686 }
687 }
688
689 /**
576 * Perform a select all action. 690 * Perform a select all action.
577 */ 691 */
578 @VisibleForTesting 692 @VisibleForTesting
579 void selectAll() { 693 void selectAll() {
580 mWebContents.selectAll(); 694 mWebContents.selectAll();
581 // Even though the above statement logged a SelectAll user action, we wa nt to 695 // Even though the above statement logged a SelectAll user action, we wa nt to
582 // track whether the focus was in an editable field, so log that too. 696 // track whether the focus was in an editable field, so log that too.
583 if (isSelectionEditable()) { 697 if (isSelectionEditable()) {
584 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); 698 RecordUserAction.record("MobileActionMode.SelectAllWasEditable");
585 } else { 699 } else {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T); 857 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T);
744 if (result != null) { 858 if (result != null) {
745 // TODO(hush): Use a variant of replace that re-selects the replaced text. 859 // TODO(hush): Use a variant of replace that re-selects the replaced text.
746 // crbug.com/546710 860 // crbug.com/546710
747 mWebContents.replace(result.toString()); 861 mWebContents.replace(result.toString());
748 } 862 }
749 } 863 }
750 864
751 void restoreSelectionPopupsIfNecessary() { 865 void restoreSelectionPopupsIfNecessary() {
752 if (mHasSelection && !isActionModeValid()) { 866 if (mHasSelection && !isActionModeValid()) {
753 if (!showActionMode()) clearSelection(); 867 showActionMode();
754 } 868 }
755 } 869 }
756 870
757 // All coordinates are in DIP. 871 // All coordinates are in DIP.
758 void onSelectionEvent(int eventType, int xAnchor, int yAnchor, 872 void onSelectionEvent(int eventType, int xAnchor, int yAnchor,
759 int left, int top, int right, int bottom, boolean isScrollInProgress , 873 int left, int top, int right, int bottom, boolean isScrollInProgress ,
760 boolean touchScrollInProgress) { 874 boolean touchScrollInProgress) {
761 // Ensure the provided selection coordinates form a non-empty rect, as r equired by 875 // Ensure the provided selection coordinates form a non-empty rect, as r equired by
762 // the selection action mode. 876 // the selection action mode.
763 if (left == right) ++right; 877 if (left == right) ++right;
764 if (top == bottom) ++bottom; 878 if (top == bottom) ++bottom;
765 switch (eventType) { 879 switch (eventType) {
766 case SelectionEventType.SELECTION_HANDLES_SHOWN: 880 case SelectionEventType.SELECTION_HANDLES_SHOWN:
767 mSelectionRect.set(left, top, right, bottom); 881 mSelectionRect.set(left, top, right, bottom);
768 mHasSelection = true; 882 mHasSelection = true;
769 mUnselectAllOnDismiss = true; 883 mUnselectAllOnDismiss = true;
770 if (!showActionMode()) clearSelection(); 884 if (mSelectionClient != null && mSelectionClient.sendsMenuUpdate s()) {
885 mPostponedDisplayOp = POSTPONED_SHOW;
886 } else {
887 showActionMode();
888 }
771 break; 889 break;
772 890
773 case SelectionEventType.SELECTION_HANDLES_MOVED: 891 case SelectionEventType.SELECTION_HANDLES_MOVED:
774 mSelectionRect.set(left, top, right, bottom); 892 mSelectionRect.set(left, top, right, bottom);
775 invalidateContentRect(); 893 invalidateContentRect();
776 break; 894 break;
777 895
778 case SelectionEventType.SELECTION_HANDLES_CLEARED: 896 case SelectionEventType.SELECTION_HANDLES_CLEARED:
779 mHasSelection = false; 897 mHasSelection = false;
780 mUnselectAllOnDismiss = false; 898 mUnselectAllOnDismiss = false;
781 mSelectionRect.setEmpty(); 899 mSelectionRect.setEmpty();
782 finishActionMode(); 900 finishActionMode();
783 break; 901 break;
784 902
785 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: 903 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
786 hideActionMode(true); 904 hideActionMode(true);
787 break; 905 break;
788 906
789 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: 907 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
790 hideActionMode(false); 908 if (mSelectionClient != null && mSelectionClient.sendsMenuUpdate s()) {
909 mPostponedDisplayOp = POSTPONED_INVALIDATE;
910 } else {
911 hideActionMode(false);
912 }
791 break; 913 break;
792 914
793 case SelectionEventType.INSERTION_HANDLE_SHOWN: 915 case SelectionEventType.INSERTION_HANDLE_SHOWN:
794 mSelectionRect.set(left, top, right, bottom); 916 mSelectionRect.set(left, top, right, bottom);
795 setIsInsertion(true); 917 setIsInsertion(true);
796 break; 918 break;
797 919
798 case SelectionEventType.INSERTION_HANDLE_MOVED: 920 case SelectionEventType.INSERTION_HANDLE_MOVED:
799 mSelectionRect.set(left, top, right, bottom); 921 mSelectionRect.set(left, top, right, bottom);
800 if (!isScrollInProgress && isPastePopupShowing()) { 922 if (!isScrollInProgress && isPastePopupShowing()) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 int yAnchorPix = (int) (yAnchor * deviceScale); 963 int yAnchorPix = (int) (yAnchor * deviceScale);
842 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ; 964 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ;
843 } 965 }
844 } 966 }
845 967
846 /** 968 /**
847 * Clears the current text selection. Note that we will try to move cursor t o selection 969 * Clears the current text selection. Note that we will try to move cursor t o selection
848 * end if applicable. 970 * end if applicable.
849 */ 971 */
850 void clearSelection() { 972 void clearSelection() {
973 mClassificationResult = null;
851 if (mWebContents == null || isEmpty()) return; 974 if (mWebContents == null || isEmpty()) return;
852 mWebContents.collapseSelection(); 975 mWebContents.collapseSelection();
853 } 976 }
854 977
855 void onSelectionChanged(String text) { 978 void onSelectionChanged(String text) {
856 mLastSelectedText = text; 979 mLastSelectedText = text;
857 if (mSelectionClient != null) { 980 if (mSelectionClient != null) {
858 mSelectionClient.onSelectionChanged(text); 981 mSelectionClient.onSelectionChanged(text);
859 } 982 }
860 } 983 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 mIsInsertion = insertion; 1033 mIsInsertion = insertion;
911 } 1034 }
912 1035
913 private boolean isShareAvailable() { 1036 private boolean isShareAvailable() {
914 Intent intent = new Intent(Intent.ACTION_SEND); 1037 Intent intent = new Intent(Intent.ACTION_SEND);
915 intent.setType("text/plain"); 1038 intent.setType("text/plain");
916 return mContext.getPackageManager().queryIntentActivities(intent, 1039 return mContext.getPackageManager().queryIntentActivities(intent,
917 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 1040 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
918 } 1041 }
919 } 1042 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698