summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Keisuke Kuroyanagi <ksk@google.com> 2015-03-16 17:44:26 +0900
committer Keisuke Kuroyanagi <ksk@google.com> 2015-04-22 15:33:27 +0900
commit05fd8d50b2ec89c760e19794b9fd2a14421009ae (patch)
tree8301cfbcd0634d485051237109572007d8fafe7f
parent7428de195086d95ddc850f387442c8c0f21e7b0f (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.java52
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).