OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 package org.chromium.content.browser; | 5 package org.chromium.content.browser; |
6 | 6 |
7 import android.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.app.Activity; | 8 import android.app.Activity; |
9 import android.app.SearchManager; | 9 import android.app.SearchManager; |
10 import android.content.ClipboardManager; | 10 import android.content.ClipboardManager; |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |