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

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

Issue 2740103006: Implement SmartText selection. (Closed)
Patch Set: ResultCallback is not a member of SelectionPopupController any more 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
« no previous file with comments | « content/public/android/java/src/org/chromium/content/browser/SelectionClient.java ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 if the selection exists and
125 // ContextSelectionProvider was able to classify it, otherwise null.
126 private ContextSelectionProvider.Result mClassificationResult;
127
128 // Postponed display operation for ActionMode.
129 //
130 // The |mSelectionClient| might perform a recognition of the selected texts that
131 // can affect the ActionMode menu. In this case its method sendsPopupMenuUpd ates()
132 // returns true and the client itself sends the results back asynchronously.
133 //
134 // With this kind of SelectionClient we postpone the display of ActionMode m enu
135 // until the result comes, so we can update the menu before showing it and a void the flicker.
136 // This variable holds the type of operation we have postponed, i.e. show or invalidate.
137 private int mPostponedDisplayOp = POSTPONED_NONE;
boliu 2017/03/22 02:32:12 should mention this is only valid and not NONE if
Tima Vaisburd 2017/03/24 22:13:55 I followed Pedro's and your advises and tried to s
138
118 /** 139 /**
119 * Create {@link SelectionPopupController} instance. 140 * Create {@link SelectionPopupController} instance.
120 * @param context Context for action mode. 141 * @param context Context for action mode.
121 * @param window WindowAndroid instance. 142 * @param window WindowAndroid instance.
122 * @param webContents WebContents instance. 143 * @param webContents WebContents instance.
123 * @param view Container view. 144 * @param view Container view.
124 * @param renderCoordinates Coordinates info used to position elements. 145 * @param renderCoordinates Coordinates info used to position elements.
125 * @param imeAdapter ImeAdapter instance to handle cursor position. 146 * @param imeAdapter ImeAdapter instance to handle cursor position.
126 */ 147 */
127 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents, 148 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents,
(...skipping 10 matching lines...) Expand all
138 mRepeatingHideRunnable = new Runnable() { 159 mRepeatingHideRunnable = new Runnable() {
139 @Override 160 @Override
140 public void run() { 161 public void run() {
141 assert mHidden; 162 assert mHidden;
142 final long hideDuration = getDefaultHideDuration(); 163 final long hideDuration = getDefaultHideDuration();
143 // Ensure the next hide call occurs before the ActionMode reappe ars. 164 // Ensure the next hide call occurs before the ActionMode reappe ars.
144 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1); 165 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1);
145 hideActionModeTemporarily(hideDuration); 166 hideActionModeTemporarily(hideDuration);
146 } 167 }
147 }; 168 };
169
170 mSelectionClient =
171 ContextSelectionClient.create(new ContextSelectionCallback(), wi ndow, webContents);
148 } 172 }
149 173
150 /** 174 /**
151 * Update the container view. 175 * Update the container view.
152 */ 176 */
153 void setContainerView(View view) { 177 void setContainerView(View view) {
154 assert view != null; 178 assert view != null;
155 179
156 // Cleans up action mode before switching to a new container view. 180 // Cleans up action mode before switching to a new container view.
157 if (isActionModeValid()) finishActionMode(); 181 if (isActionModeValid()) finishActionMode();
(...skipping 24 matching lines...) Expand all
182 @Override 206 @Override
183 public void setAllowedMenuItems(int allowedMenuItems) { 207 public void setAllowedMenuItems(int allowedMenuItems) {
184 mAllowedMenuItems = allowedMenuItems; 208 mAllowedMenuItems = allowedMenuItems;
185 } 209 }
186 210
187 /** 211 /**
188 * Show (activate) android action mode by starting it. 212 * Show (activate) android action mode by starting it.
189 * 213 *
190 * <p>Action mode in floating mode is tried first, and then falls back to 214 * <p>Action mode in floating mode is tried first, and then falls back to
191 * a normal one. 215 * a normal one.
192 * @return {@code true} if the action mode started successfully or is alread y on. 216 * <p> If the action mode cannot be created the selection is cleared.
193 */ 217 */
194 public boolean showActionMode() { 218 public void showActionModeOrClearOnFailure() {
195 if (isEmpty()) return false; 219 if (isEmpty()) {
220 clearSelection();
221 return;
222 }
196 223
197 // Just refreshes the view if it is already showing. 224 // Just refreshes the view if it is already showing.
198 if (isActionModeValid()) { 225 if (isActionModeValid()) {
199 invalidateActionMode(); 226 invalidateActionMode();
200 return true; 227 return;
201 } 228 }
202 229
203 if (mView.getParent() != null) { 230 if (mView.getParent() != null) {
204 // On ICS, startActionMode throws an NPE when getParent() is null. 231 // On ICS, startActionMode throws an NPE when getParent() is null.
205 assert mWebContents != null; 232 assert mWebContents != null;
206 ActionMode actionMode = supportsFloatingActionMode() 233 ActionMode actionMode = supportsFloatingActionMode()
207 ? startFloatingActionMode() 234 ? startFloatingActionMode()
208 : mView.startActionMode(mCallback); 235 : mView.startActionMode(mCallback);
209 if (actionMode != null) { 236 if (actionMode != null) {
210 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details. 237 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details.
211 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ; 238 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ;
212 } 239 }
213 mActionMode = actionMode; 240 mActionMode = actionMode;
214 } 241 }
215 mUnselectAllOnDismiss = true; 242 mUnselectAllOnDismiss = true;
216 return isActionModeValid(); 243 if (!isActionModeValid()) clearSelection();
217 } 244 }
218 245
219 @TargetApi(Build.VERSION_CODES.M) 246 @TargetApi(Build.VERSION_CODES.M)
220 private ActionMode startFloatingActionMode() { 247 private ActionMode startFloatingActionMode() {
221 ActionMode actionMode = mView.startActionMode( 248 ActionMode actionMode = mView.startActionMode(
222 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); 249 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING);
223 return actionMode; 250 return actionMode;
224 } 251 }
225 252
226 void showPastePopup(int x, int y) { 253 void showPastePopup(int x, int y) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 return mPastePopupMenu != null && mPastePopupMenu.isShowing(); 315 return mPastePopupMenu != null && mPastePopupMenu.isShowing();
289 } 316 }
290 317
291 // Composition methods for android.view.ActionMode 318 // Composition methods for android.view.ActionMode
292 319
293 /** 320 /**
294 * @see ActionMode#finish() 321 * @see ActionMode#finish()
295 */ 322 */
296 @Override 323 @Override
297 public void finishActionMode() { 324 public void finishActionMode() {
325 mPostponedDisplayOp = POSTPONED_NONE;
boliu 2017/03/22 02:32:12 reset mClassificationResult here too?
Tima Vaisburd 2017/03/24 22:13:55 I wanted to associate mClassificationResult with t
298 if (isActionModeValid()) { 326 if (isActionModeValid()) {
299 mActionMode.finish(); 327 mActionMode.finish();
300 328
301 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response. 329 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response.
302 mActionMode = null; 330 mActionMode = null;
303 } 331 }
304 } 332 }
305 333
306 /** 334 /**
307 * @see ActionMode#invalidate() 335 * @see ActionMode#invalidate()
308 * Note that invalidation will also reset visibility state. The caller 336 * Note that invalidation will also reset visibility state. The caller
309 * should account for this when making subsequent visibility updates. 337 * should account for this when making subsequent visibility updates.
310 */ 338 */
311 private void invalidateActionMode() { 339 private void invalidateActionMode() {
312 if (!isActionModeValid()) return; 340 if (!isActionModeValid()) return;
313 if (mHidden) { 341 if (mHidden) {
314 assert canHideActionMode(); 342 assert canHideActionMode();
315 mHidden = false; 343 mHidden = false;
boliu 2017/03/22 02:32:12 so... 343-345 is a repeated at 392-394, factor out
Tima Vaisburd 2017/03/24 22:13:55 This code changed. Since I do not try to invalidat
316 mView.removeCallbacks(mRepeatingHideRunnable); 344 mView.removeCallbacks(mRepeatingHideRunnable);
345 hideActionModeTemporarily(SHOW_DELAY_MS);
317 mPendingInvalidateContentRect = false; 346 mPendingInvalidateContentRect = false;
318 } 347 }
319 348
320 // Try/catch necessary for framework bug, crbug.com/446717. 349 // Try/catch necessary for framework bug, crbug.com/446717.
321 try { 350 try {
322 mActionMode.invalidate(); 351 mActionMode.invalidate();
323 } catch (NullPointerException e) { 352 } catch (NullPointerException e) {
324 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e); 353 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e);
325 } 354 }
326 } 355 }
327 356
328 /** 357 /**
329 * @see ActionMode#invalidateContentRect() 358 * @see ActionMode#invalidateContentRect()
330 */ 359 */
331 public void invalidateContentRect() { 360 private void invalidateContentRect() {
332 if (supportsFloatingActionMode()) { 361 if (supportsFloatingActionMode()) {
333 if (mHidden) { 362 if (mHidden) {
334 mPendingInvalidateContentRect = true; 363 mPendingInvalidateContentRect = true;
335 } else { 364 } else {
336 mPendingInvalidateContentRect = false; 365 mPendingInvalidateContentRect = false;
337 if (isActionModeValid()) mActionMode.invalidateContentRect(); 366 if (isActionModeValid()) mActionMode.invalidateContentRect();
338 } 367 }
339 } 368 }
340 } 369 }
341 370
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // caused a resource loading failure to be logged. WebView 453 // caused a resource loading failure to be logged. WebView
425 // resource access needs to be improved so that this 454 // resource access needs to be improved so that this
426 // logspam can be avoided. 455 // logspam can be avoided.
427 new MenuInflater(context).inflate(R.menu.select_action_menu, menu); 456 new MenuInflater(context).inflate(R.menu.select_action_menu, menu);
428 } 457 }
429 } 458 }
430 459
431 private void createActionMenu(ActionMode mode, Menu menu) { 460 private void createActionMenu(ActionMode mode, Menu menu) {
432 mNeedsPrepare = false; 461 mNeedsPrepare = false;
433 initializeMenu(mContext, mode, menu); 462 initializeMenu(mContext, mode, menu);
463 updateContextDependentMenuItem(menu);
434 464
435 if (!isSelectionEditable() || !canPaste()) { 465 if (!isSelectionEditable() || !canPaste()) {
436 menu.removeItem(R.id.select_action_menu_paste); 466 menu.removeItem(R.id.select_action_menu_paste);
437 } 467 }
438 468
439 if (isInsertion()) { 469 if (isInsertion()) {
440 menu.removeItem(R.id.select_action_menu_select_all); 470 menu.removeItem(R.id.select_action_menu_select_all);
441 menu.removeItem(R.id.select_action_menu_cut); 471 menu.removeItem(R.id.select_action_menu_cut);
442 menu.removeItem(R.id.select_action_menu_copy); 472 menu.removeItem(R.id.select_action_menu_copy);
443 menu.removeItem(R.id.select_action_menu_share); 473 menu.removeItem(R.id.select_action_menu_share);
(...skipping 22 matching lines...) Expand all
466 496
467 initializeTextProcessingMenu(menu); 497 initializeTextProcessingMenu(menu);
468 } 498 }
469 499
470 private boolean canPaste() { 500 private boolean canPaste() {
471 ClipboardManager clipMgr = (ClipboardManager) 501 ClipboardManager clipMgr = (ClipboardManager)
472 mContext.getSystemService(Context.CLIPBOARD_SERVICE); 502 mContext.getSystemService(Context.CLIPBOARD_SERVICE);
473 return clipMgr.hasPrimaryClip(); 503 return clipMgr.hasPrimaryClip();
474 } 504 }
475 505
506 private void updateContextDependentMenuItem(Menu menu) {
507 MenuItem assistItem = menu.findItem(R.id.select_action_menu_context_dep) ;
508 if (assistItem == null) return;
509
510 if (mClassificationResult == null) {
511 assistItem.setVisible(false).setEnabled(false);
512 } else {
513 assistItem.setVisible(true)
514 .setEnabled(true)
515 .setTitle(mClassificationResult.label)
516 .setIcon(mClassificationResult.icon);
517 }
518 }
519
476 /** 520 /**
477 * Intialize the menu items for processing text, if there is any. 521 * Intialize the menu items for processing text, if there is any.
478 */ 522 */
479 private void initializeTextProcessingMenu(Menu menu) { 523 private void initializeTextProcessingMenu(Menu menu) {
480 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M 524 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
481 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) { 525 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) {
482 return; 526 return;
483 } 527 }
484 528
485 PackageManager packageManager = mContext.getPackageManager(); 529 PackageManager packageManager = mContext.getPackageManager();
486 List<ResolveInfo> supportedActivities = 530 List<ResolveInfo> supportedActivities =
487 packageManager.queryIntentActivities(createProcessTextIntent(), 0); 531 packageManager.queryIntentActivities(createProcessTextIntent(), 0);
488 for (int i = 0; i < supportedActivities.size(); i++) { 532 for (int i = 0; i < supportedActivities.size(); i++) {
489 ResolveInfo resolveInfo = supportedActivities.get(i); 533 ResolveInfo resolveInfo = supportedActivities.get(i);
490 CharSequence label = resolveInfo.loadLabel(mContext.getPackageManage r()); 534 CharSequence label = resolveInfo.loadLabel(mContext.getPackageManage r());
491 menu.add(R.id.select_action_menu_text_processing_menus, Menu.NONE, i , label) 535 menu.add(R.id.select_action_menu_text_processing_menus, Menu.NONE, M enu.NONE, label)
492 .setIntent(createProcessTextIntentForResolveInfo(resolveInfo )) 536 .setIntent(createProcessTextIntentForResolveInfo(resolveInfo ))
493 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 537 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
494 } 538 }
495 } 539 }
496 540
497 @TargetApi(Build.VERSION_CODES.M) 541 @TargetApi(Build.VERSION_CODES.M)
498 private static Intent createProcessTextIntent() { 542 private static Intent createProcessTextIntent() {
499 return new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/ plain"); 543 return new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/ plain");
500 } 544 }
501 545
502 @TargetApi(Build.VERSION_CODES.M) 546 @TargetApi(Build.VERSION_CODES.M)
503 private Intent createProcessTextIntentForResolveInfo(ResolveInfo info) { 547 private Intent createProcessTextIntentForResolveInfo(ResolveInfo info) {
504 boolean isReadOnly = !isSelectionEditable(); 548 boolean isReadOnly = !isSelectionEditable();
505 return createProcessTextIntent() 549 return createProcessTextIntent()
506 .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, isReadOnly) 550 .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, isReadOnly)
507 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame); 551 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame);
508 } 552 }
509 553
510 @Override 554 @Override
511 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 555 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
512 if (!isActionModeValid()) return true; 556 if (!isActionModeValid()) return true;
513 557
514 int id = item.getItemId(); 558 int id = item.getItemId();
515 int groupId = item.getGroupId(); 559 int groupId = item.getGroupId();
516 560
517 if (id == R.id.select_action_menu_select_all) { 561 if (id == R.id.select_action_menu_context_dep) {
562 doContextDependentAction();
563 mode.finish();
564 } else if (id == R.id.select_action_menu_select_all) {
518 selectAll(); 565 selectAll();
519 } else if (id == R.id.select_action_menu_cut) { 566 } else if (id == R.id.select_action_menu_cut) {
520 cut(); 567 cut();
521 mode.finish(); 568 mode.finish();
522 } else if (id == R.id.select_action_menu_copy) { 569 } else if (id == R.id.select_action_menu_copy) {
523 copy(); 570 copy();
524 mode.finish(); 571 mode.finish();
525 } else if (id == R.id.select_action_menu_paste) { 572 } else if (id == R.id.select_action_menu_paste) {
526 paste(); 573 paste();
527 mode.finish(); 574 mode.finish();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 (int) (mSelectionRect.top * deviceScale), 613 (int) (mSelectionRect.top * deviceScale),
567 (int) (mSelectionRect.right * deviceScale), 614 (int) (mSelectionRect.right * deviceScale),
568 (int) (mSelectionRect.bottom * deviceScale)); 615 (int) (mSelectionRect.bottom * deviceScale));
569 616
570 // The selection coordinates are relative to the content viewport, but w e need 617 // The selection coordinates are relative to the content viewport, but w e need
571 // coordinates relative to the containing View. 618 // coordinates relative to the containing View.
572 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix()); 619 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
573 } 620 }
574 621
575 /** 622 /**
623 * Perform an action that depends on the semantics of the selected text.
624 */
625 @VisibleForTesting
626 void doContextDependentAction() {
627 if (mClassificationResult == null) return;
628
629 assert mClassificationResult.onClickListener != null
630 || mClassificationResult.intent != null;
631
632 if (mClassificationResult.onClickListener != null) {
633 mClassificationResult.onClickListener.onClick(mView);
634 return;
635 }
636
637 if (mClassificationResult.intent != null) {
638 Context context = mWindowAndroid.getContext().get();
639 if (context == null) return;
640
641 context.startActivity(mClassificationResult.intent);
642 return;
643 }
644 }
645
646 /**
576 * Perform a select all action. 647 * Perform a select all action.
577 */ 648 */
578 @VisibleForTesting 649 @VisibleForTesting
579 void selectAll() { 650 void selectAll() {
580 mWebContents.selectAll(); 651 mWebContents.selectAll();
581 // Even though the above statement logged a SelectAll user action, we wa nt to 652 // 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. 653 // track whether the focus was in an editable field, so log that too.
583 if (isSelectionEditable()) { 654 if (isSelectionEditable()) {
584 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); 655 RecordUserAction.record("MobileActionMode.SelectAllWasEditable");
585 } else { 656 } else {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T); 814 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T);
744 if (result != null) { 815 if (result != null) {
745 // TODO(hush): Use a variant of replace that re-selects the replaced text. 816 // TODO(hush): Use a variant of replace that re-selects the replaced text.
746 // crbug.com/546710 817 // crbug.com/546710
747 mWebContents.replace(result.toString()); 818 mWebContents.replace(result.toString());
748 } 819 }
749 } 820 }
750 821
751 void restoreSelectionPopupsIfNecessary() { 822 void restoreSelectionPopupsIfNecessary() {
752 if (mHasSelection && !isActionModeValid()) { 823 if (mHasSelection && !isActionModeValid()) {
753 if (!showActionMode()) clearSelection(); 824 showActionModeOrClearOnFailure();
754 } 825 }
755 } 826 }
756 827
757 // All coordinates are in DIP. 828 // All coordinates are in DIP.
758 void onSelectionEvent(int eventType, int xAnchor, int yAnchor, 829 void onSelectionEvent(int eventType, int xAnchor, int yAnchor,
759 int left, int top, int right, int bottom, boolean isScrollInProgress , 830 int left, int top, int right, int bottom, boolean isScrollInProgress ,
760 boolean touchScrollInProgress) { 831 boolean touchScrollInProgress) {
761 // Ensure the provided selection coordinates form a non-empty rect, as r equired by 832 // Ensure the provided selection coordinates form a non-empty rect, as r equired by
762 // the selection action mode. 833 // the selection action mode.
763 if (left == right) ++right; 834 if (left == right) ++right;
764 if (top == bottom) ++bottom; 835 if (top == bottom) ++bottom;
765 switch (eventType) { 836 switch (eventType) {
766 case SelectionEventType.SELECTION_HANDLES_SHOWN: 837 case SelectionEventType.SELECTION_HANDLES_SHOWN:
767 mSelectionRect.set(left, top, right, bottom); 838 mSelectionRect.set(left, top, right, bottom);
768 mHasSelection = true; 839 mHasSelection = true;
769 mUnselectAllOnDismiss = true; 840 mUnselectAllOnDismiss = true;
770 if (!showActionMode()) clearSelection(); 841 if (mSelectionClient != null && mSelectionClient.sendsSelectionP opupUpdates()) {
842 mPostponedDisplayOp = POSTPONED_SHOW;
843 } else {
844 showActionModeOrClearOnFailure();
845 }
771 break; 846 break;
772 847
773 case SelectionEventType.SELECTION_HANDLES_MOVED: 848 case SelectionEventType.SELECTION_HANDLES_MOVED:
774 mSelectionRect.set(left, top, right, bottom); 849 mSelectionRect.set(left, top, right, bottom);
775 invalidateContentRect(); 850 invalidateContentRect();
776 break; 851 break;
777 852
778 case SelectionEventType.SELECTION_HANDLES_CLEARED: 853 case SelectionEventType.SELECTION_HANDLES_CLEARED:
779 mHasSelection = false; 854 mHasSelection = false;
780 mUnselectAllOnDismiss = false; 855 mUnselectAllOnDismiss = false;
781 mSelectionRect.setEmpty(); 856 mSelectionRect.setEmpty();
782 finishActionMode(); 857 finishActionMode();
783 break; 858 break;
784 859
785 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: 860 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
786 hideActionMode(true); 861 hideActionMode(true);
787 break; 862 break;
788 863
789 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: 864 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
790 hideActionMode(false); 865 if (mSelectionClient != null && mSelectionClient.sendsSelectionP opupUpdates()) {
866 mPostponedDisplayOp = POSTPONED_INVALIDATE;
867 } else {
868 hideActionMode(false);
869 }
791 break; 870 break;
792 871
793 case SelectionEventType.INSERTION_HANDLE_SHOWN: 872 case SelectionEventType.INSERTION_HANDLE_SHOWN:
794 mSelectionRect.set(left, top, right, bottom); 873 mSelectionRect.set(left, top, right, bottom);
795 setIsInsertion(true); 874 setIsInsertion(true);
796 break; 875 break;
797 876
798 case SelectionEventType.INSERTION_HANDLE_MOVED: 877 case SelectionEventType.INSERTION_HANDLE_MOVED:
799 mSelectionRect.set(left, top, right, bottom); 878 mSelectionRect.set(left, top, right, bottom);
800 if (!isScrollInProgress && isPastePopupShowing()) { 879 if (!isScrollInProgress && isPastePopupShowing()) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 int yAnchorPix = (int) (yAnchor * deviceScale); 920 int yAnchorPix = (int) (yAnchor * deviceScale);
842 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ; 921 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ;
843 } 922 }
844 } 923 }
845 924
846 /** 925 /**
847 * Clears the current text selection. Note that we will try to move cursor t o selection 926 * Clears the current text selection. Note that we will try to move cursor t o selection
848 * end if applicable. 927 * end if applicable.
849 */ 928 */
850 void clearSelection() { 929 void clearSelection() {
930 mClassificationResult = null;
851 if (mWebContents == null || isEmpty()) return; 931 if (mWebContents == null || isEmpty()) return;
852 mWebContents.collapseSelection(); 932 mWebContents.collapseSelection();
853 } 933 }
854 934
855 void onSelectionChanged(String text) { 935 void onSelectionChanged(String text) {
856 mLastSelectedText = text; 936 mLastSelectedText = text;
857 if (mSelectionClient != null) { 937 if (mSelectionClient != null) {
858 mSelectionClient.onSelectionChanged(text); 938 mSelectionClient.onSelectionChanged(text);
859 } 939 }
860 } 940 }
861 941
862 // The client that implements selection augmenting functionality, or null if none exists. 942 // The client that implements selection augmenting functionality, or null if none exists.
863 void setSelectionClient(SelectionClient selectionClient) { 943 void setSelectionClient(SelectionClient selectionClient) {
864 mSelectionClient = selectionClient; 944 mSelectionClient = selectionClient;
boliu 2017/03/22 02:32:12 probably want to reset some state here?
Tima Vaisburd 2017/03/24 22:13:55 Done.
865 } 945 }
866 946
867 void onShowUnhandledTapUIIfNeeded(int x, int y) { 947 void onShowUnhandledTapUIIfNeeded(int x, int y) {
868 if (mSelectionClient != null) { 948 if (mSelectionClient != null) {
869 mSelectionClient.showUnhandledTapUIIfNeeded(x, y); 949 mSelectionClient.showUnhandledTapUIIfNeeded(x, y);
870 } 950 }
871 } 951 }
872 952
873 void destroyActionModeAndUnselect() { 953 void destroyActionModeAndUnselect() {
874 mUnselectAllOnDismiss = true; 954 mUnselectAllOnDismiss = true;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
909 if (isActionModeValid() && mIsInsertion != insertion) mNeedsPrepare = tr ue; 989 if (isActionModeValid() && mIsInsertion != insertion) mNeedsPrepare = tr ue;
910 mIsInsertion = insertion; 990 mIsInsertion = insertion;
911 } 991 }
912 992
913 private boolean isShareAvailable() { 993 private boolean isShareAvailable() {
914 Intent intent = new Intent(Intent.ACTION_SEND); 994 Intent intent = new Intent(Intent.ACTION_SEND);
915 intent.setType("text/plain"); 995 intent.setType("text/plain");
916 return mContext.getPackageManager().queryIntentActivities(intent, 996 return mContext.getPackageManager().queryIntentActivities(intent,
917 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 997 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
918 } 998 }
999
1000 // The callback class that delivers result from a ContextSelectionClient.
1001 private class ContextSelectionCallback implements ContextSelectionProvider.R esultCallback {
1002 @Override
1003 public void onClassified(ContextSelectionProvider.Result result) {
1004 // If the selection does not exist any more, discard |result|.
1005 if (!mHasSelection) {
1006 mPostponedDisplayOp = POSTPONED_NONE;
1007 return;
1008 }
1009
1010 // Update the selection range if needed.
1011 if (!(result.startAdjust == 0 && result.endAdjust == 0)) {
1012 // This call causes SELECTION_HANDLES_MOVED event
1013 mWebContents.adjustSelectionByCharacterOffset(result.startAdjust , result.endAdjust);
1014 }
1015
1016 final boolean hadPriorResult = mClassificationResult != null;
1017 mClassificationResult = result.hasNamedAction() ? result : null;
1018
1019 // For simplicity always update the menu if we need to show assist i tem.
1020 // Also we need to update the menu if the assist item is going to di sappear.
1021 if (mClassificationResult != null || hadPriorResult) mNeedsPrepare = true;
1022
1023 switch (mPostponedDisplayOp) {
1024 case POSTPONED_NONE:
1025 break;
1026
1027 case POSTPONED_SHOW:
1028 // TODO(timav): if the |result| contained the selection adju stment and
1029 // we called adjustSelectionByCharacterOffset() above, there is a
1030 // flicker if SELECTION_HANDLES_MOVED comes later and invali dates the
1031 // selection rectangle. Consider postponing till SELECTION_H ANDLES_MOVED
1032 // or introduce delay.
1033 showActionModeOrClearOnFailure();
1034 mPostponedDisplayOp = POSTPONED_NONE;
1035 break;
1036
1037 case POSTPONED_INVALIDATE:
1038 invalidateActionMode();
1039 mPostponedDisplayOp = POSTPONED_NONE;
1040 break;
1041
1042 default:
1043 assert false : "Invalid postponed display operation type.";
1044 break;
1045 }
1046 }
1047 };
919 } 1048 }
OLDNEW
« no previous file with comments | « content/public/android/java/src/org/chromium/content/browser/SelectionClient.java ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698