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

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

Issue 2740103006: Implement SmartText selection. (Closed)
Patch Set: 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
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 private boolean mHasSelection; 108 private boolean mHasSelection;
109 109
110 // Lazily created paste popup menu, triggered either via long press in an 110 // Lazily created paste popup menu, triggered either via long press in an
111 // editable region or from tapping the insertion handle. 111 // editable region or from tapping the insertion handle.
112 private PastePopupMenu mPastePopupMenu; 112 private PastePopupMenu mPastePopupMenu;
113 private boolean mWasPastePopupShowingOnInsertionDragStart; 113 private boolean mWasPastePopupShowingOnInsertionDragStart;
114 114
115 // The client that processes textual selection, or null if none exists. 115 // The client that processes textual selection, or null if none exists.
116 private SelectionClient mSelectionClient; 116 private SelectionClient mSelectionClient;
117 117
118 // The classificaton result of the selected text or null if ContextSelection Provider
119 // could not classify the selection.
120 private ContextSelectionProvider.Result mClassificationResult;
boliu 2017/03/11 00:47:00 this should be invalidated somewhere, right?
Tima Vaisburd 2017/03/20 05:06:04 Yes, this is a bug, thank you. I invalidated in cl
121
122 // Display action mode operation (show or invalidate) that is postponed unti l the selected
123 // text is classified.
124 private static final int POSTPONED_NONE = 0;
boliu 2017/03/11 00:37:52 constants at the top
125 private static final int POSTPONED_SHOW = 1;
126 private static final int POSTPONED_INVALIDATE = 2;
127
128 // Postponed display operation for ActionMode
129 private int mPostponedDisplayOp;
boliu 2017/03/11 00:47:00 I think it's ok to be a bit wordy here describing
Tima Vaisburd 2017/03/20 05:06:04 Not done yet.
130
131 // The callback object that delivers result from SelectionClient.
132 private ContextSelectionProvider.ResultCallback mSelectonCallback =
133 new ContextSelectionProvider.ResultCallback() {
134 @Override
135 public void onClassified(ContextSelectionProvider.Result result) {
136 Log.v(TAG, "onClassified");
137
138 // If the selection does not exist any more, discard |result |.
139 if (!mHasSelection) {
140 mPostponedDisplayOp = POSTPONED_NONE;
141 return;
142 }
143
144 // Update the selection range if needed.
145 if (!(result.startAdjust == 0 && result.endAdjust == 0)) {
146 // This call causes SELECTION_HANDLES_MOVED event
147 mWebContents.adjustSelectionByCharacterOffset(
148 result.startAdjust, result.endAdjust);
149 }
150
151 final boolean hadPriorResult = mClassificationResult != null ;
152 mClassificationResult = result.hasNamedAction() ? result : n ull;
153
154 // For simplicity always update the menu if we need to show assist item.
155 // Also we need to update the menu if the assist item is goi ng to disappear.
156 if (mClassificationResult != null || hadPriorResult) mNeedsP repare = true;
157
158 switch (mPostponedDisplayOp) {
159 case POSTPONED_NONE:
160 break;
161
162 case POSTPONED_SHOW:
163 // TODO(timav): if the |result| contained the select ion adjustment and
164 // we called adjustSelectionByCharacterOffset() abov e, there is flicker
165 // if SELECTION_HANDLES_MOVED comes later and invali dates selection
166 // rectangle. Consider postponing till SELECTION_HAN DLES_MOVED or
167 // introduce delay.
168 showActionModeOrClearSelection();
169 mPostponedDisplayOp = POSTPONED_NONE;
170 break;
171
172 case POSTPONED_INVALIDATE:
173 invalidateActionMode();
174 mPostponedDisplayOp = POSTPONED_NONE;
175 break;
176
177 default:
178 assert false : "Invalid postponed display operation type.";
179 break;
180 }
181 }
182 };
183
118 /** 184 /**
119 * Create {@link SelectionPopupController} instance. 185 * Create {@link SelectionPopupController} instance.
120 * @param context Context for action mode. 186 * @param context Context for action mode.
121 * @param window WindowAndroid instance. 187 * @param window WindowAndroid instance.
122 * @param webContents WebContents instance. 188 * @param webContents WebContents instance.
123 * @param view Container view. 189 * @param view Container view.
124 * @param renderCoordinates Coordinates info used to position elements. 190 * @param renderCoordinates Coordinates info used to position elements.
125 * @param imeAdapter ImeAdapter instance to handle cursor position. 191 * @param imeAdapter ImeAdapter instance to handle cursor position.
126 */ 192 */
127 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents, 193 public SelectionPopupController(Context context, WindowAndroid window, WebCo ntents webContents,
(...skipping 10 matching lines...) Expand all
138 mRepeatingHideRunnable = new Runnable() { 204 mRepeatingHideRunnable = new Runnable() {
139 @Override 205 @Override
140 public void run() { 206 public void run() {
141 assert mHidden; 207 assert mHidden;
142 final long hideDuration = getDefaultHideDuration(); 208 final long hideDuration = getDefaultHideDuration();
143 // Ensure the next hide call occurs before the ActionMode reappe ars. 209 // Ensure the next hide call occurs before the ActionMode reappe ars.
144 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1); 210 mView.postDelayed(mRepeatingHideRunnable, hideDuration - 1);
145 hideActionModeTemporarily(hideDuration); 211 hideActionModeTemporarily(hideDuration);
146 } 212 }
147 }; 213 };
214
215 mSelectionClient = ContextSelectionClient.create(mSelectonCallback, wind ow, webContents);
148 } 216 }
149 217
150 /** 218 /**
151 * Update the container view. 219 * Update the container view.
152 */ 220 */
153 void setContainerView(View view) { 221 void setContainerView(View view) {
154 assert view != null; 222 assert view != null;
155 223
156 // Cleans up action mode before switching to a new container view. 224 // Cleans up action mode before switching to a new container view.
157 if (isActionModeValid()) finishActionMode(); 225 if (isActionModeValid()) finishActionMode();
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 return mPastePopupMenu != null && mPastePopupMenu.isShowing(); 356 return mPastePopupMenu != null && mPastePopupMenu.isShowing();
289 } 357 }
290 358
291 // Composition methods for android.view.ActionMode 359 // Composition methods for android.view.ActionMode
292 360
293 /** 361 /**
294 * @see ActionMode#finish() 362 * @see ActionMode#finish()
295 */ 363 */
296 @Override 364 @Override
297 public void finishActionMode() { 365 public void finishActionMode() {
366 mPostponedDisplayOp = POSTPONED_NONE;
298 if (isActionModeValid()) { 367 if (isActionModeValid()) {
299 mActionMode.finish(); 368 mActionMode.finish();
300 369
301 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response. 370 // Should be nulled out in case #onDestroyActionMode() is not invoke d in response.
302 mActionMode = null; 371 mActionMode = null;
303 } 372 }
304 } 373 }
305 374
306 /** 375 /**
307 * @see ActionMode#invalidate() 376 * @see ActionMode#invalidate()
308 * Note that invalidation will also reset visibility state. The caller 377 * Note that invalidation will also reset visibility state. The caller
309 * should account for this when making subsequent visibility updates. 378 * should account for this when making subsequent visibility updates.
310 */ 379 */
311 private void invalidateActionMode() { 380 private void invalidateActionMode() {
312 if (!isActionModeValid()) return; 381 if (!isActionModeValid()) return;
313 if (mHidden) { 382 if (mHidden) {
314 assert canHideActionMode(); 383 assert canHideActionMode();
315 mHidden = false; 384 mHidden = false;
316 mView.removeCallbacks(mRepeatingHideRunnable); 385 mView.removeCallbacks(mRepeatingHideRunnable);
386 hideActionModeTemporarily(SHOW_DELAY_MS);
boliu 2017/03/11 00:37:52 why?
Tima Vaisburd 2017/03/20 05:06:05 This is a fix, I believe this invalidate() from hi
boliu 2017/03/20 20:27:25 That makes no sense. This is not a hide operaion,
Tima Vaisburd 2017/03/21 02:07:01 I agree this is confusing. It looks like I'm hidin
317 mPendingInvalidateContentRect = false; 387 mPendingInvalidateContentRect = false;
318 } 388 }
319 389
320 // Try/catch necessary for framework bug, crbug.com/446717. 390 // Try/catch necessary for framework bug, crbug.com/446717.
321 try { 391 try {
322 mActionMode.invalidate(); 392 mActionMode.invalidate();
323 } catch (NullPointerException e) { 393 } catch (NullPointerException e) {
324 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e); 394 Log.w(TAG, "Ignoring NPE from ActionMode.invalidate() as workaround for L", e);
325 } 395 }
326 } 396 }
327 397
328 /** 398 /**
329 * @see ActionMode#invalidateContentRect() 399 * @see ActionMode#invalidateContentRect()
330 */ 400 */
331 public void invalidateContentRect() { 401 private void invalidateContentRect() {
332 if (supportsFloatingActionMode()) { 402 if (supportsFloatingActionMode()) {
333 if (mHidden) { 403 if (mHidden) {
334 mPendingInvalidateContentRect = true; 404 mPendingInvalidateContentRect = true;
335 } else { 405 } else {
336 mPendingInvalidateContentRect = false; 406 mPendingInvalidateContentRect = false;
337 if (isActionModeValid()) mActionMode.invalidateContentRect(); 407 if (isActionModeValid()) mActionMode.invalidateContentRect();
338 } 408 }
339 } 409 }
340 } 410 }
341 411
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 // caused a resource loading failure to be logged. WebView 494 // caused a resource loading failure to be logged. WebView
425 // resource access needs to be improved so that this 495 // resource access needs to be improved so that this
426 // logspam can be avoided. 496 // logspam can be avoided.
427 new MenuInflater(context).inflate(R.menu.select_action_menu, menu); 497 new MenuInflater(context).inflate(R.menu.select_action_menu, menu);
428 } 498 }
429 } 499 }
430 500
431 private void createActionMenu(ActionMode mode, Menu menu) { 501 private void createActionMenu(ActionMode mode, Menu menu) {
432 mNeedsPrepare = false; 502 mNeedsPrepare = false;
433 initializeMenu(mContext, mode, menu); 503 initializeMenu(mContext, mode, menu);
504 updateContextDependantMenuItem(menu);
434 505
435 if (!isSelectionEditable() || !canPaste()) { 506 if (!isSelectionEditable() || !canPaste()) {
436 menu.removeItem(R.id.select_action_menu_paste); 507 menu.removeItem(R.id.select_action_menu_paste);
437 } 508 }
438 509
439 if (isInsertion()) { 510 if (isInsertion()) {
440 menu.removeItem(R.id.select_action_menu_select_all); 511 menu.removeItem(R.id.select_action_menu_select_all);
441 menu.removeItem(R.id.select_action_menu_cut); 512 menu.removeItem(R.id.select_action_menu_cut);
442 menu.removeItem(R.id.select_action_menu_copy); 513 menu.removeItem(R.id.select_action_menu_copy);
443 menu.removeItem(R.id.select_action_menu_share); 514 menu.removeItem(R.id.select_action_menu_share);
(...skipping 22 matching lines...) Expand all
466 537
467 initializeTextProcessingMenu(menu); 538 initializeTextProcessingMenu(menu);
468 } 539 }
469 540
470 private boolean canPaste() { 541 private boolean canPaste() {
471 ClipboardManager clipMgr = (ClipboardManager) 542 ClipboardManager clipMgr = (ClipboardManager)
472 mContext.getSystemService(Context.CLIPBOARD_SERVICE); 543 mContext.getSystemService(Context.CLIPBOARD_SERVICE);
473 return clipMgr.hasPrimaryClip(); 544 return clipMgr.hasPrimaryClip();
474 } 545 }
475 546
547 private void updateContextDependantMenuItem(Menu menu) {
548 Log.v(TAG, "updateContextDependantItem");
549 menu.removeItem(R.id.select_action_menu_context_dep);
550
551 if (mClassificationResult == null) return;
552
553 Log.v(TAG, "updateContextDependantMenuItem: adding item " + mClassificat ionResult.label);
554 menu.add(Menu.NONE, R.id.select_action_menu_context_dep, 1, mClassificat ionResult.label)
555 .setIcon(mClassificationResult.icon)
556 .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
557 }
558
476 /** 559 /**
477 * Intialize the menu items for processing text, if there is any. 560 * Intialize the menu items for processing text, if there is any.
478 */ 561 */
479 private void initializeTextProcessingMenu(Menu menu) { 562 private void initializeTextProcessingMenu(Menu menu) {
480 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M 563 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
481 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) { 564 || !isSelectActionModeAllowed(MENU_ITEM_PROCESS_TEXT)) {
482 return; 565 return;
483 } 566 }
484 567
485 PackageManager packageManager = mContext.getPackageManager(); 568 PackageManager packageManager = mContext.getPackageManager();
(...skipping 21 matching lines...) Expand all
507 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame); 590 .setClassName(info.activityInfo.packageName, info.activityInfo.n ame);
508 } 591 }
509 592
510 @Override 593 @Override
511 public boolean onActionItemClicked(ActionMode mode, MenuItem item) { 594 public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
512 if (!isActionModeValid()) return true; 595 if (!isActionModeValid()) return true;
513 596
514 int id = item.getItemId(); 597 int id = item.getItemId();
515 int groupId = item.getGroupId(); 598 int groupId = item.getGroupId();
516 599
517 if (id == R.id.select_action_menu_select_all) { 600 if (id == R.id.select_action_menu_context_dep) {
601 doContextDependentAction();
602 mode.finish();
603 } else if (id == R.id.select_action_menu_select_all) {
518 selectAll(); 604 selectAll();
519 } else if (id == R.id.select_action_menu_cut) { 605 } else if (id == R.id.select_action_menu_cut) {
520 cut(); 606 cut();
521 mode.finish(); 607 mode.finish();
522 } else if (id == R.id.select_action_menu_copy) { 608 } else if (id == R.id.select_action_menu_copy) {
523 copy(); 609 copy();
524 mode.finish(); 610 mode.finish();
525 } else if (id == R.id.select_action_menu_paste) { 611 } else if (id == R.id.select_action_menu_paste) {
526 paste(); 612 paste();
527 mode.finish(); 613 mode.finish();
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
566 (int) (mSelectionRect.top * deviceScale), 652 (int) (mSelectionRect.top * deviceScale),
567 (int) (mSelectionRect.right * deviceScale), 653 (int) (mSelectionRect.right * deviceScale),
568 (int) (mSelectionRect.bottom * deviceScale)); 654 (int) (mSelectionRect.bottom * deviceScale));
569 655
570 // The selection coordinates are relative to the content viewport, but w e need 656 // The selection coordinates are relative to the content viewport, but w e need
571 // coordinates relative to the containing View. 657 // coordinates relative to the containing View.
572 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix()); 658 outRect.offset(0, (int) mRenderCoordinates.getContentOffsetYPix());
573 } 659 }
574 660
575 /** 661 /**
662 * Perform an action that depends on the semantics of the selected text.
663 */
664 @VisibleForTesting
665 void doContextDependentAction() {
666 if (mClassificationResult == null) return;
667
668 assert mClassificationResult.onClickListener != null
669 || mClassificationResult.intent != null;
670
671 if (mClassificationResult.onClickListener != null) {
672 mClassificationResult.onClickListener.onClick(mView);
673 return;
674 }
675
676 if (mClassificationResult.intent != null) {
677 Context context = mWindowAndroid.getContext().get();
678 if (context == null) return;
679
680 context.startActivity(mClassificationResult.intent);
681 return;
682 }
683 }
684
685 /**
576 * Perform a select all action. 686 * Perform a select all action.
577 */ 687 */
578 @VisibleForTesting 688 @VisibleForTesting
579 void selectAll() { 689 void selectAll() {
580 mWebContents.selectAll(); 690 mWebContents.selectAll();
581 // Even though the above statement logged a SelectAll user action, we wa nt to 691 // 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. 692 // track whether the focus was in an editable field, so log that too.
583 if (isSelectionEditable()) { 693 if (isSelectionEditable()) {
584 RecordUserAction.record("MobileActionMode.SelectAllWasEditable"); 694 RecordUserAction.record("MobileActionMode.SelectAllWasEditable");
585 } else { 695 } else {
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
743 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T); 853 CharSequence result = data.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEX T);
744 if (result != null) { 854 if (result != null) {
745 // TODO(hush): Use a variant of replace that re-selects the replaced text. 855 // TODO(hush): Use a variant of replace that re-selects the replaced text.
746 // crbug.com/546710 856 // crbug.com/546710
747 mWebContents.replace(result.toString()); 857 mWebContents.replace(result.toString());
748 } 858 }
749 } 859 }
750 860
751 void restoreSelectionPopupsIfNecessary() { 861 void restoreSelectionPopupsIfNecessary() {
752 if (mHasSelection && !isActionModeValid()) { 862 if (mHasSelection && !isActionModeValid()) {
753 if (!showActionMode()) clearSelection(); 863 showActionModeOrClearSelection();
754 } 864 }
755 } 865 }
756 866
867 private void showActionModeOrClearSelection() {
boliu 2017/03/11 00:37:52 clearSelectionIfNotShowingActionMode?
Tima Vaisburd 2017/03/20 05:06:04 It seems I can simply clear selection inside showA
868 if (!showActionMode()) clearSelection();
869 }
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;
Tima Vaisburd 2017/03/10 20:42:37 I thought about sending the postponed operation to
boliu 2017/03/11 00:37:52 Yeah I'm thinking of the exactly same thing readin
Tima Vaisburd 2017/03/11 01:22:17 Yes, and I prefer explicit actions like "doThis" i
886 } else {
887 showActionModeOrClearSelection();
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 109 matching lines...) Expand 10 before | Expand all | Expand 10 after
910 mIsInsertion = insertion; 1032 mIsInsertion = insertion;
911 } 1033 }
912 1034
913 private boolean isShareAvailable() { 1035 private boolean isShareAvailable() {
914 Intent intent = new Intent(Intent.ACTION_SEND); 1036 Intent intent = new Intent(Intent.ACTION_SEND);
915 intent.setType("text/plain"); 1037 intent.setType("text/plain");
916 return mContext.getPackageManager().queryIntentActivities(intent, 1038 return mContext.getPackageManager().queryIntentActivities(intent,
917 PackageManager.MATCH_DEFAULT_ONLY).size() > 0; 1039 PackageManager.MATCH_DEFAULT_ONLY).size() > 0;
918 } 1040 }
919 } 1041 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698