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

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

Issue 2740103006: Implement SmartText selection. (Closed)
Patch Set: Addressed 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
« 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;
138
139 // The callback object that delivers result from SelectionClient.
140 private ContextSelectionProvider.ResultCallback mSelectonCallback =
141 new ContextSelectionProvider.ResultCallback() {
142 @Override
143 public void onClassified(ContextSelectionProvider.Result result) {
144 // If the selection does not exist any more, discard |result |.
145 if (!mHasSelection) {
146 mPostponedDisplayOp = POSTPONED_NONE;
147 return;
148 }
149
150 // Update the selection range if needed.
151 if (!(result.startAdjust == 0 && result.endAdjust == 0)) {
152 // This call causes SELECTION_HANDLES_MOVED event
153 mWebContents.adjustSelectionByCharacterOffset(
154 result.startAdjust, result.endAdjust);
155 }
156
157 final boolean hadPriorResult = mClassificationResult != null ;
158 mClassificationResult = result.hasNamedAction() ? result : n ull;
159
160 // For simplicity always update the menu if we need to show assist item.
161 // Also we need to update the menu if the assist item is goi ng to disappear.
162 if (mClassificationResult != null || hadPriorResult) mNeedsP repare = true;
163
164 switch (mPostponedDisplayOp) {
165 case POSTPONED_NONE:
166 break;
167
168 case POSTPONED_SHOW:
169 // TODO(timav): if the |result| contained the select ion adjustment and
170 // we called adjustSelectionByCharacterOffset() abov e, there is a
171 // flicker if SELECTION_HANDLES_MOVED comes later an d invalidates the
172 // selection rectangle. Consider postponing till SEL ECTION_HANDLES_MOVED
173 // or introduce delay.
174 showActionModeOrClearOnFailure();
175 mPostponedDisplayOp = POSTPONED_NONE;
176 break;
177
178 case POSTPONED_INVALIDATE:
179 invalidateActionMode();
180 mPostponedDisplayOp = POSTPONED_NONE;
181 break;
182
183 default:
184 assert false : "Invalid postponed display operation type.";
185 break;
186 }
187 }
188 };
189
118 /** 190 /**
119 * Create {@link SelectionPopupController} instance. 191 * Create {@link SelectionPopupController} instance.
120 * @param context Context for action mode. 192 * @param context Context for action mode.
121 * @param window WindowAndroid instance. 193 * @param window WindowAndroid instance.
122 * @param webContents WebContents instance. 194 * @param webContents WebContents instance.
123 * @param view Container view. 195 * @param view Container view.
124 * @param renderCoordinates Coordinates info used to position elements. 196 * @param renderCoordinates Coordinates info used to position elements.
125 * @param imeAdapter ImeAdapter instance to handle cursor position. 197 * @param imeAdapter ImeAdapter instance to handle cursor position.
126 */ 198 */
127 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents, 199 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents,
(...skipping 10 matching lines...) Expand all
138 mRepeatingHideRunnable = new Runnable() { 210 mRepeatingHideRunnable = new Runnable() {
139 @Override 211 @Override
140 public void run() { 212 public void run() {
141 assert mHidden; 213 assert mHidden;
142 final long hideDuration = getDefaultHideDuration(); 214 final long hideDuration = getDefaultHideDuration();
143 // Ensure the next hide call occurs before the ActionMode reappe ars. 215 // Ensure the next hide call occurs before the ActionMode reappe ars.
144 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1); 216 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1);
145 hideActionModeTemporarily(hideDuration); 217 hideActionModeTemporarily(hideDuration);
146 } 218 }
147 }; 219 };
220
221 mSelectionClient = ContextSelectionClient.create(mSelectonCallback, wind ow, webContents);
148 } 222 }
149 223
150 /** 224 /**
151 * Update the container view. 225 * Update the container view.
152 */ 226 */
153 void setContainerView(View view) { 227 void setContainerView(View view) {
154 assert view != null; 228 assert view != null;
155 229
156 // Cleans up action mode before switching to a new container view. 230 // Cleans up action mode before switching to a new container view.
157 if (isActionModeValid()) finishActionMode(); 231 if (isActionModeValid()) finishActionMode();
(...skipping 24 matching lines...) Expand all
182 @Override 256 @Override
183 public void setAllowedMenuItems(int allowedMenuItems) { 257 public void setAllowedMenuItems(int allowedMenuItems) {
184 mAllowedMenuItems = allowedMenuItems; 258 mAllowedMenuItems = allowedMenuItems;
185 } 259 }
186 260
187 /** 261 /**
188 * Show (activate) android action mode by starting it. 262 * Show (activate) android action mode by starting it.
189 * 263 *
190 * <p>Action mode in floating mode is tried first, and then falls back to 264 * <p>Action mode in floating mode is tried first, and then falls back to
191 * a normal one. 265 * a normal one.
192 * @return {@code true} if the action mode started successfully or is alread y on. 266 * <p> If the action mode cannot be created the selection is cleared.
193 */ 267 */
194 public boolean showActionMode() { 268 public void showActionModeOrClearOnFailure() {
195 if (isEmpty()) return false; 269 if (isEmpty()) {
270 clearSelection();
271 return;
272 }
196 273
197 // Just refreshes the view if it is already showing. 274 // Just refreshes the view if it is already showing.
198 if (isActionModeValid()) { 275 if (isActionModeValid()) {
199 invalidateActionMode(); 276 invalidateActionMode();
200 return true; 277 return;
201 } 278 }
202 279
203 if (mView.getParent() != null) { 280 if (mView.getParent() != null) {
204 // On ICS, startActionMode throws an NPE when getParent() is null. 281 // On ICS, startActionMode throws an NPE when getParent() is null.
205 assert mWebContents != null; 282 assert mWebContents != null;
206 ActionMode actionMode = supportsFloatingActionMode() 283 ActionMode actionMode = supportsFloatingActionMode()
207 ? startFloatingActionMode() 284 ? startFloatingActionMode()
208 : mView.startActionMode(mCallback); 285 : mView.startActionMode(mCallback);
209 if (actionMode != null) { 286 if (actionMode != null) {
210 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details. 287 // This is to work around an LGE email issue. See crbug.com/6517 06 for more details.
211 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ; 288 LGEmailActionModeWorkaround.runIfNecessary(mContext, actionMode) ;
212 } 289 }
213 mActionMode = actionMode; 290 mActionMode = actionMode;
214 } 291 }
215 mUnselectAllOnDismiss = true; 292 mUnselectAllOnDismiss = true;
216 return isActionModeValid(); 293 if (!isActionModeValid()) clearSelection();
217 } 294 }
218 295
219 @TargetApi(Build.VERSION_CODES.M) 296 @TargetApi(Build.VERSION_CODES.M)
220 private ActionMode startFloatingActionMode() { 297 private ActionMode startFloatingActionMode() {
221 ActionMode actionMode = mView.startActionMode( 298 ActionMode actionMode = mView.startActionMode(
222 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING); 299 new FloatingActionModeCallback(this, mCallback), ActionMode.TYPE _FLOATING);
223 return actionMode; 300 return actionMode;
224 } 301 }
225 302
226 void showPastePopup(int x, int y) { 303 void showPastePopup(int x, int y) {
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 return mPastePopupMenu != null && mPastePopupMenu.isShowing(); 365 return mPastePopupMenu != null && mPastePopupMenu.isShowing();
289 } 366 }
290 367
291 // Composition methods for android.view.ActionMode 368 // Composition methods for android.view.ActionMode
292 369
293 /** 370 /**
294 * @see ActionMode#finish() 371 * @see ActionMode#finish()
295 */ 372 */
296 @Override 373 @Override
297 public void finishActionMode() { 374 public void finishActionMode() {
375 mPostponedDisplayOp = POSTPONED_NONE;
298 if (isActionModeValid()) { 376 if (isActionModeValid()) {
299 mActionMode.finish(); 377 mActionMode.finish();
300 378
301 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response. 379 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response.
302 mActionMode = null; 380 mActionMode = null;
303 } 381 }
304 } 382 }
305 383
306 /** 384 /**
307 * @see ActionMode#invalidate() 385 * @see ActionMode#invalidate()
308 * Note that invalidation will also reset visibility state. The caller 386 * Note that invalidation will also reset visibility state. The caller
309 * should account for this when making subsequent visibility updates. 387 * should account for this when making subsequent visibility updates.
310 */ 388 */
311 private void invalidateActionMode() { 389 private void invalidateActionMode() {
312 if (!isActionModeValid()) return; 390 if (!isActionModeValid()) return;
313 if (mHidden) { 391 if (mHidden) {
314 assert canHideActionMode(); 392 assert canHideActionMode();
315 mHidden = false; 393 mHidden = false;
316 mView.removeCallbacks(mRepeatingHideRunnable); 394 mView.removeCallbacks(mRepeatingHideRunnable);
395 hideActionModeTemporarily(SHOW_DELAY_MS);
317 mPendingInvalidateContentRect = false; 396 mPendingInvalidateContentRect = false;
318 } 397 }
319 398
320 // Try/catch necessary for framework bug, crbug.com/446717. 399 // Try/catch necessary for framework bug, crbug.com/446717.
321 try { 400 try {
322 mActionMode.invalidate(); 401 mActionMode.invalidate();
323 } catch (NullPointerException e) { 402 } catch (NullPointerException e) {
324 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e); 403 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e);
325 } 404 }
326 } 405 }
327 406
328 /** 407 /**
329 * @see ActionMode#invalidateContentRect() 408 * @see ActionMode#invalidateContentRect()
330 */ 409 */
331 public void invalidateContentRect() { 410 private void invalidateContentRect() {
332 if (supportsFloatingActionMode()) { 411 if (supportsFloatingActionMode()) {
333 if (mHidden) { 412 if (mHidden) {
334 mPendingInvalidateContentRect = true; 413 mPendingInvalidateContentRect = true;
335 } else { 414 } else {
336 mPendingInvalidateContentRect = false; 415 mPendingInvalidateContentRect = false;
337 if (isActionModeValid()) mActionMode.invalidateContentRect(); 416 if (isActionModeValid()) mActionMode.invalidateContentRect();
338 } 417 }
339 } 418 }
340 } 419 }
341 420
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // caused a resource loading failure to be logged. WebView 503 // caused a resource loading failure to be logged. WebView
425 // resource access needs to be improved so that this 504 // resource access needs to be improved so that this
426 // logspam can be avoided. 505 // logspam can be avoided.
427 new MenuInflater(context).inflate(R.menu.select_action_menu, menu); 506 new MenuInflater(context).inflate(R.menu.select_action_menu, menu);
428 } 507 }
429 } 508 }
430 509
431 private void createActionMenu(ActionMode mode, Menu menu) { 510 private void createActionMenu(ActionMode mode, Menu menu) {
432 mNeedsPrepare = false; 511 mNeedsPrepare = false;
433 initializeMenu(mContext, mode, menu); 512 initializeMenu(mContext, mode, menu);
513 updateContextDependentMenuItem(menu);
434 514
435 if (!isSelectionEditable() || !canPaste()) { 515 if (!isSelectionEditable() || !canPaste()) {
436 menu.removeItem(R.id.select_action_menu_paste); 516 menu.removeItem(R.id.select_action_menu_paste);
437 } 517 }
438 518
439 if (isInsertion()) { 519 if (isInsertion()) {
440 menu.removeItem(R.id.select_action_menu_select_all); 520 menu.removeItem(R.id.select_action_menu_select_all);
441 menu.removeItem(R.id.select_action_menu_cut); 521 menu.removeItem(R.id.select_action_menu_cut);
442 menu.removeItem(R.id.select_action_menu_copy); 522 menu.removeItem(R.id.select_action_menu_copy);
443 menu.removeItem(R.id.select_action_menu_share); 523 menu.removeItem(R.id.select_action_menu_share);
(...skipping 22 matching lines...) Expand all
466 546
467 initializeTextProcessingMenu(menu); 547 initializeTextProcessingMenu(menu);
468 } 548 }
469 549
470 private boolean canPaste() { 550 private boolean canPaste() {
471 ClipboardManager clipMgr = (ClipboardManager) 551 ClipboardManager clipMgr = (ClipboardManager)
472 mContext.getSystemService(Context.CLIPBOARD_SERVICE); 552 mContext.getSystemService(Context.CLIPBOARD_SERVICE);
473 return clipMgr.hasPrimaryClip(); 553 return clipMgr.hasPrimaryClip();
474 } 554 }
475 555
556 private void updateContextDependentMenuItem(Menu menu) {
557 MenuItem assistItem = menu.findItem(R.id.select_action_menu_context_dep) ;
558 if (assistItem == null) return;
559
560 if (mClassificationResult == null) {
561 assistItem.setVisible(false).setEnabled(false);
562 } else {
563 assistItem.setVisible(true)
564 .setEnabled(true)
565 .setTitle(mClassificationResult.label)
566 .setIcon(mClassificationResult.icon);
567 }
568 }
569
476 /** 570 /**
477 * Intialize the menu items for processing text, if there is any. 571 * Intialize the menu items for processing text, if there is any.
478 */ 572 */
479 private void initializeTextProcessingMenu(Menu menu) { 573 private void initializeTextProcessingMenu(Menu menu) {
480 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M 574 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
481 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) { 575 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) {
482 return; 576 return;
483 } 577 }
484 578
485 PackageManager packageManager = mContext.getPackageManager(); 579 PackageManager packageManager = mContext.getPackageManager();
486 List<ResolveInfo> supportedActivities = 580 List<ResolveInfo> supportedActivities =
487 packageManager.queryIntentActivities(createProcessTextIntent(), 0); 581 packageManager.queryIntentActivities(createProcessTextIntent(), 0);
488 for (int i = 0; i < supportedActivities.size(); i++) { 582 for (int i = 0; i < supportedActivities.size(); i++) {
489 ResolveInfo resolveInfo = supportedActivities.get(i); 583 ResolveInfo resolveInfo = supportedActivities.get(i);
490 CharSequence label = resolveInfo.loadLabel(mContext.getPackageManage r()); 584 CharSequence label = resolveInfo.loadLabel(mContext.getPackageManage r());
491 menu.add(R.id.select_action_menu_text_processing_menus, Menu.NONE, i , label) 585 menu.add(R.id.select_action_menu_text_processing_menus, Menu.NONE, M enu.NONE, label)
Tima Vaisburd 2017/03/21 02:07:02 Here i==0 and i==1 for the order have different se
492 .setIntent(createProcessTextIntentForResolveInfo(resolveInfo )) 586 .setIntent(createProcessTextIntentForResolveInfo(resolveInfo ))
493 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); 587 .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
494 } 588 }
495 } 589 }
496 590
497 @TargetApi(Build.VERSION_CODES.M) 591 @TargetApi(Build.VERSION_CODES.M)
498 private static Intent createProcessTextIntent() { 592 private static Intent createProcessTextIntent() {
499 return new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/ plain"); 593 return new Intent().setAction(Intent.ACTION_PROCESS_TEXT).setType("text/ plain");
500 } 594 }
501 595
502 @TargetApi(Build.VERSION_CODES.M) 596 @TargetApi(Build.VERSION_CODES.M)
503 private Intent createProcessTextIntentForResolveInfo(ResolveInfo info) { 597 private Intent createProcessTextIntentForResolveInfo(ResolveInfo info) {
504 boolean isReadOnly = !isSelectionEditable(); 598 boolean isReadOnly = !isSelectionEditable();
505 return createProcessTextIntent() 599 return createProcessTextIntent()
506 .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, isReadOnly) 600 .putExtra(Intent.EXTRA_PROCESS_TEXT_READONLY, isReadOnly)
507 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame); 601 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame);
508 } 602 }
509 603
510 @Override 604 @Override
511 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 605 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
512 if (!isActionModeValid()) return true; 606 if (!isActionModeValid()) return true;
513 607
514 int id = item.getItemId(); 608 int id = item.getItemId();
515 int groupId = item.getGroupId(); 609 int groupId = item.getGroupId();
516 610
517 if (id == R.id.select_action_menu_select_all) { 611 if (id == R.id.select_action_menu_context_dep) {
612 doContextDependentAction();
613 mode.finish();
614 } else if (id == R.id.select_action_menu_select_all) {
518 selectAll(); 615 selectAll();
519 } else if (id == R.id.select_action_menu_cut) { 616 } else if (id == R.id.select_action_menu_cut) {
520 cut(); 617 cut();
521 mode.finish(); 618 mode.finish();
522 } else if (id == R.id.select_action_menu_copy) { 619 } else if (id == R.id.select_action_menu_copy) {
523 copy(); 620 copy();
524 mode.finish(); 621 mode.finish();
525 } else if (id == R.id.select_action_menu_paste) { 622 } else if (id == R.id.select_action_menu_paste) {
526 paste(); 623 paste();
527 mode.finish(); 624 mode.finish();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 (int) (mSelectionRect.top * deviceScale), 663 (int) (mSelectionRect.top * deviceScale),
567 (int) (mSelectionRect.right * deviceScale), 664 (int) (mSelectionRect.right * deviceScale),
568 (int) (mSelectionRect.bottom * deviceScale)); 665 (int) (mSelectionRect.bottom * deviceScale));
569 666
570 // The selection coordinates are relative to the content viewport, but w e need 667 // The selection coordinates are relative to the content viewport, but w e need
571 // coordinates relative to the containing View. 668 // coordinates relative to the containing View.
572 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix()); 669 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
573 } 670 }
574 671
575 /** 672 /**
673 * Perform an action that depends on the semantics of the selected text.
674 */
675 @VisibleForTesting
676 void doContextDependentAction() {
677 if (mClassificationResult == null) return;
678
679 assert mClassificationResult.onClickListener != null
680 || mClassificationResult.intent != null;
681
682 if (mClassificationResult.onClickListener != null) {
683 mClassificationResult.onClickListener.onClick(mView);
684 return;
685 }
686
687 if (mClassificationResult.intent != null) {
688 Context context = mWindowAndroid.getContext().get();
689 if (context == null) return;
690
691 context.startActivity(mClassificationResult.intent);
692 return;
693 }
694 }
695
696 /**
576 * Perform a select all action. 697 * Perform a select all action.
577 */ 698 */
578 @VisibleForTesting 699 @VisibleForTesting
579 void selectAll() { 700 void selectAll() {
580 mWebContents.selectAll(); 701 mWebContents.selectAll();
581 // Even though the above statement logged a SelectAll user action, we wa nt to 702 // 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. 703 // track whether the focus was in an editable field, so log that too.
583 if (isSelectionEditable()) { 704 if (isSelectionEditable()) {
584 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); 705 RecordUserAction.record("MobileActionMode.SelectAllWasEditable");
585 } else { 706 } else {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T); 864 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T);
744 if (result != null) { 865 if (result != null) {
745 // TODO(hush): Use a variant of replace that re-selects the replaced text. 866 // TODO(hush): Use a variant of replace that re-selects the replaced text.
746 // crbug.com/546710 867 // crbug.com/546710
747 mWebContents.replace(result.toString()); 868 mWebContents.replace(result.toString());
748 } 869 }
749 } 870 }
750 871
751 void restoreSelectionPopupsIfNecessary() { 872 void restoreSelectionPopupsIfNecessary() {
752 if (mHasSelection && !isActionModeValid()) { 873 if (mHasSelection && !isActionModeValid()) {
753 if (!showActionMode()) clearSelection(); 874 showActionModeOrClearOnFailure();
754 } 875 }
755 } 876 }
756 877
757 // All coordinates are in DIP. 878 // All coordinates are in DIP.
758 void onSelectionEvent(int eventType, int xAnchor, int yAnchor, 879 void onSelectionEvent(int eventType, int xAnchor, int yAnchor,
759 int left, int top, int right, int bottom, boolean isScrollInProgress , 880 int left, int top, int right, int bottom, boolean isScrollInProgress ,
760 boolean touchScrollInProgress) { 881 boolean touchScrollInProgress) {
761 // Ensure the provided selection coordinates form a non-empty rect, as r equired by 882 // Ensure the provided selection coordinates form a non-empty rect, as r equired by
762 // the selection action mode. 883 // the selection action mode.
763 if (left == right) ++right; 884 if (left == right) ++right;
764 if (top == bottom) ++bottom; 885 if (top == bottom) ++bottom;
765 switch (eventType) { 886 switch (eventType) {
766 case SelectionEventType.SELECTION_HANDLES_SHOWN: 887 case SelectionEventType.SELECTION_HANDLES_SHOWN:
767 mSelectionRect.set(left, top, right, bottom); 888 mSelectionRect.set(left, top, right, bottom);
768 mHasSelection = true; 889 mHasSelection = true;
769 mUnselectAllOnDismiss = true; 890 mUnselectAllOnDismiss = true;
770 if (!showActionMode()) clearSelection(); 891 if (mSelectionClient != null && mSelectionClient.sendsSelectionP opupUpdates()) {
892 mPostponedDisplayOp = POSTPONED_SHOW;
893 } else {
894 showActionModeOrClearOnFailure();
895 }
771 break; 896 break;
772 897
773 case SelectionEventType.SELECTION_HANDLES_MOVED: 898 case SelectionEventType.SELECTION_HANDLES_MOVED:
774 mSelectionRect.set(left, top, right, bottom); 899 mSelectionRect.set(left, top, right, bottom);
775 invalidateContentRect(); 900 invalidateContentRect();
776 break; 901 break;
777 902
778 case SelectionEventType.SELECTION_HANDLES_CLEARED: 903 case SelectionEventType.SELECTION_HANDLES_CLEARED:
779 mHasSelection = false; 904 mHasSelection = false;
780 mUnselectAllOnDismiss = false; 905 mUnselectAllOnDismiss = false;
781 mSelectionRect.setEmpty(); 906 mSelectionRect.setEmpty();
782 finishActionMode(); 907 finishActionMode();
783 break; 908 break;
784 909
785 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED: 910 case SelectionEventType.SELECTION_HANDLE_DRAG_STARTED:
786 hideActionMode(true); 911 hideActionMode(true);
787 break; 912 break;
788 913
789 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED: 914 case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
790 hideActionMode(false); 915 if (mSelectionClient != null && mSelectionClient.sendsSelectionP opupUpdates()) {
916 mPostponedDisplayOp = POSTPONED_INVALIDATE;
917 } else {
918 hideActionMode(false);
919 }
791 break; 920 break;
792 921
793 case SelectionEventType.INSERTION_HANDLE_SHOWN: 922 case SelectionEventType.INSERTION_HANDLE_SHOWN:
794 mSelectionRect.set(left, top, right, bottom); 923 mSelectionRect.set(left, top, right, bottom);
795 setIsInsertion(true); 924 setIsInsertion(true);
796 break; 925 break;
797 926
798 case SelectionEventType.INSERTION_HANDLE_MOVED: 927 case SelectionEventType.INSERTION_HANDLE_MOVED:
799 mSelectionRect.set(left, top, right, bottom); 928 mSelectionRect.set(left, top, right, bottom);
800 if (!isScrollInProgress && isPastePopupShowing()) { 929 if (!isScrollInProgress && isPastePopupShowing()) {
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
841 int yAnchorPix = (int) (yAnchor * deviceScale); 970 int yAnchorPix = (int) (yAnchor * deviceScale);
842 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ; 971 mSelectionClient.onSelectionEvent(eventType, xAnchorPix, yAnchorPix) ;
843 } 972 }
844 } 973 }
845 974
846 /** 975 /**
847 * Clears the current text selection. Note that we will try to move cursor t o selection 976 * Clears the current text selection. Note that we will try to move cursor t o selection
848 * end if applicable. 977 * end if applicable.
849 */ 978 */
850 void clearSelection() { 979 void clearSelection() {
980 mClassificationResult = null;
851 if (mWebContents == null || isEmpty()) return; 981 if (mWebContents == null || isEmpty()) return;
852 mWebContents.collapseSelection(); 982 mWebContents.collapseSelection();
853 } 983 }
854 984
855 void onSelectionChanged(String text) { 985 void onSelectionChanged(String text) {
856 mLastSelectedText = text; 986 mLastSelectedText = text;
857 if (mSelectionClient != null) { 987 if (mSelectionClient != null) {
858 mSelectionClient.onSelectionChanged(text); 988 mSelectionClient.onSelectionChanged(text);
859 } 989 }
860 } 990 }
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 mIsInsertion = insertion; 1040 mIsInsertion = insertion;
911 } 1041 }
912 1042
913 private boolean isShareAvailable() { 1043 private boolean isShareAvailable() {
914 Intent intent = new Intent(Intent.ACTION_SEND); 1044 Intent intent = new Intent(Intent.ACTION_SEND);
915 intent.setType("text/plain"); 1045 intent.setType("text/plain");
916 return mContext.getPackageManager().queryIntentActivities(intent, 1046 return mContext.getPackageManager().queryIntentActivities(intent,
917 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 1047 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
918 } 1048 }
919 } 1049 }
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