diff options
| author | 2015-03-16 17:44:26 +0900 | |
|---|---|---|
| committer | 2015-04-22 15:33:27 +0900 | |
| commit | 05fd8d50b2ec89c760e19794b9fd2a14421009ae (patch) | |
| tree | 8301cfbcd0634d485051237109572007d8fafe7f | |
| parent | 7428de195086d95ddc850f387442c8c0f21e7b0f (diff) | |
Stop showing "Replace" when selection isn't inside spans.
Currently, "Replace" is shown when any spans intersects
the selection. It causes confusing behavior when multiple
words are selected. "Replace" is in the ActionBar, but it's
unclear which word will be replaced. It can happen when
text is selected using long tap + drag, unig keyboard, or
using a mouse.
Bug: 19396964
Change-Id: I512f5f566d4060cd0aa7b28594054bf4f6bf7458
| -rw-r--r-- | core/java/android/widget/Editor.java | 52 |
1 files changed, 46 insertions, 6 deletions
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 955ad06814cb..c766d93bae9c 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -1764,15 +1764,55 @@ public class Editor { } /** - * @return <code>true</code> if the cursor/current selection overlaps a {@link SuggestionSpan}. + * @return <code>true</code> if it's reasonable to offer to show suggestions depending on + * the current cursor position or selection range. This method is consistent with the + * method to show suggestions {@link SuggestionsPopupWindow#updateSuggestions}. */ - private boolean isCursorInsideSuggestionSpan() { + private boolean shouldOfferToShowSuggestions() { CharSequence text = mTextView.getText(); if (!(text instanceof Spannable)) return false; - SuggestionSpan[] suggestionSpans = ((Spannable) text).getSpans( - mTextView.getSelectionStart(), mTextView.getSelectionEnd(), SuggestionSpan.class); - return (suggestionSpans.length > 0); + final Spannable spannable = (Spannable) text; + final int selectionStart = mTextView.getSelectionStart(); + final int selectionEnd = mTextView.getSelectionEnd(); + final SuggestionSpan[] suggestionSpans = spannable.getSpans(selectionStart, selectionEnd, + SuggestionSpan.class); + if (suggestionSpans.length == 0) { + return false; + } + if (selectionStart == selectionEnd) { + // Spans overlap the cursor. + return true; + } + int minSpanStart = mTextView.getText().length(); + int maxSpanEnd = 0; + int unionOfSpansCoveringSelectionStartStart = mTextView.getText().length(); + int unionOfSpansCoveringSelectionStartEnd = 0; + for (int i = 0; i < suggestionSpans.length; i++) { + final int spanStart = spannable.getSpanStart(suggestionSpans[i]); + final int spanEnd = spannable.getSpanEnd(suggestionSpans[i]); + minSpanStart = Math.min(minSpanStart, spanStart); + maxSpanEnd = Math.max(maxSpanEnd, spanEnd); + if (selectionStart < spanStart || selectionStart > spanEnd) { + // The span doesn't cover the current selection start point. + continue; + } + unionOfSpansCoveringSelectionStartStart = + Math.min(unionOfSpansCoveringSelectionStartStart, spanStart); + unionOfSpansCoveringSelectionStartEnd = + Math.max(unionOfSpansCoveringSelectionStartEnd, spanEnd); + } + if (unionOfSpansCoveringSelectionStartStart >= unionOfSpansCoveringSelectionStartEnd) { + // No spans cover the selection start point. + return false; + } + if (minSpanStart < unionOfSpansCoveringSelectionStartStart + || maxSpanEnd > unionOfSpansCoveringSelectionStartEnd) { + // There is a span that is not covered by the union. In this case, we soouldn't offer + // to show suggestions as it's confusing. + return false; + } + return true; } /** @@ -3104,7 +3144,7 @@ public class Editor { } private void updateReplaceItem(Menu menu) { - boolean canReplace = mTextView.isSuggestionsEnabled() && isCursorInsideSuggestionSpan(); + boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions(); boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null; if (canReplace && !replaceItemExists) { menu.add(0, TextView.ID_REPLACE, 0, com.android.internal.R.string.replace). |