From d319450307fcbd1f3dd99bf647c2c0281eb18e34 Mon Sep 17 00:00:00 2001 From: Keisuke Kuroyanagi Date: Fri, 26 Feb 2016 16:09:12 -0800 Subject: [PATCH] Try to find equivalent SuggestionsSpan when it has been updated. Suggestion pickup was canceled when SuggestionsSpan corresponding to the suggestion cannot be found. This was a problem when suggestion is selected in extracted mode. Selection is cleared just before creating SuggestionsPopup. The selection update is reported to the original EditText and it will invoke TextView#setExtractedText of the extracted one. In this method, SuggestionSpans are replaced with the new SuggestionSpans that usually have the same contents as the old SuggestionSpans. This CL re-enables "Replace" item in extracted mode. Bug: 22038802 Change-Id: I74bb813b110fb2f633b8578790d14039755f2d79 --- core/java/android/widget/Editor.java | 70 ++++++++++++++++++---------- 1 file changed, 46 insertions(+), 24 deletions(-) diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 5bc68ddabd81a..f693ce797a5eb 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -2515,8 +2515,37 @@ public class Editor { mPreserveDetachedSelection = true; } - private void replaceWithSuggestion(SuggestionInfo suggestionInfo, int spanStart, int spanEnd) { + private void replaceWithSuggestion(final SuggestionInfo suggestionInfo) { final Editable editable = (Editable) mTextView.getText(); + if (editable.getSpanStart(suggestionInfo.mSuggestionSpan) < 0) { + // Suggestion span coundn't be found. Try to find a suggestion span that has the same + // contents. + final SuggestionSpan[] suggestionSpans = editable.getSpans( + suggestionInfo.mSuggestionSpanStart, suggestionInfo.mSuggestionSpanEnd, + SuggestionSpan.class); + for (final SuggestionSpan suggestionSpan : suggestionSpans) { + final int spanStart = editable.getSpanStart(suggestionSpan); + if (spanStart != suggestionInfo.mSuggestionSpanStart) { + continue; + } + int spanEnd = editable.getSpanEnd(suggestionSpan); + if (spanEnd != suggestionInfo.mSuggestionSpanEnd) { + continue; + } + if (suggestionSpan.equals(suggestionInfo.mSuggestionSpan)) { + // Found. + suggestionInfo.mSuggestionSpan = suggestionSpan; + break; + } + } + } + final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan); + final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan); + if (spanStart < 0 || spanEnd <= spanStart) { + // Span has been removed + return; + } + final String originalText = TextUtils.substring(editable, spanStart, spanEnd); // SuggestionSpans are removed by replace: save them before SuggestionSpan[] suggestionSpans = editable.getSpans(spanStart, spanEnd, @@ -2590,11 +2619,7 @@ public class Editor { clear(); return false; } - final Spannable spannable = (Spannable) mTextView.getText(); - final SuggestionSpan suggestionSpan = - mSuggestionInfosInContextMenu[index].mSuggestionSpan; - replaceWithSuggestion(mSuggestionInfosInContextMenu[index], - spannable.getSpanStart(suggestionSpan), spannable.getSpanEnd(suggestionSpan)); + replaceWithSuggestion(mSuggestionInfosInContextMenu[index]); clear(); return true; } @@ -3025,13 +3050,19 @@ public class Editor { } private static class SuggestionInfo { - // Range of actual suggestion within text + // Range of actual suggestion within mText int mSuggestionStart, mSuggestionEnd; // The SuggestionSpan that this TextView represents @Nullable SuggestionSpan mSuggestionSpan; + // The SuggestionSpan start position + int mSuggestionSpanStart; + + // The SuggestionSpan end position + int mSuggestionSpanEnd; + // The index of this suggestion inside suggestionSpan int mSuggestionIndex; @@ -3138,6 +3169,8 @@ public class Editor { suggestionInfo.mSuggestionIndex = suggestionIndex; suggestionInfo.mSuggestionStart = 0; suggestionInfo.mSuggestionEnd = suggestion.length(); + suggestionInfo.mSuggestionSpanStart = spanStart; + suggestionInfo.mSuggestionSpanEnd = spanEnd; suggestionInfo.mText.replace(0, suggestionInfo.mText.length(), suggestion); numberOfSuggestions++; if (numberOfSuggestions >= suggestionInfos.length) { @@ -3429,10 +3462,8 @@ public class Editor { if ((suggestionSpan.getFlags() & SuggestionSpan.FLAG_MISSPELLED) != 0) { mMisspelledSpan = suggestionSpan; } - final int spanStart = spannable.getSpanStart(suggestionSpan); - final int spanEnd = spannable.getSpanEnd(suggestionSpan); - spanUnionStart = Math.min(spanUnionStart, spanStart); - spanUnionEnd = Math.max(spanUnionEnd, spanEnd); + spanUnionStart = Math.min(spanUnionStart, suggestionInfo.mSuggestionSpanStart); + spanUnionEnd = Math.max(spanUnionEnd, suggestionInfo.mSuggestionSpanEnd); } for (int i = 0; i < mNumberOfSuggestions; i++) { @@ -3471,8 +3502,8 @@ public class Editor { private void highlightTextDifferences(SuggestionInfo suggestionInfo, int unionStart, int unionEnd) { final Spannable text = (Spannable) mTextView.getText(); - final int spanStart = text.getSpanStart(suggestionInfo.mSuggestionSpan); - final int spanEnd = text.getSpanEnd(suggestionInfo.mSuggestionSpan); + final int spanStart = suggestionInfo.mSuggestionSpanStart; + final int spanEnd = suggestionInfo.mSuggestionSpanEnd; // Adjust the start/end of the suggestion span suggestionInfo.mSuggestionStart = spanStart - unionStart; @@ -3490,16 +3521,8 @@ public class Editor { @Override public void onItemClick(AdapterView parent, View view, int position, long id) { - Editable editable = (Editable) mTextView.getText(); SuggestionInfo suggestionInfo = mSuggestionInfos[position]; - final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan); - final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan); - if (spanStart < 0 || spanEnd <= spanStart) { - // Span has been removed - hideWithCleanUp(); - return; - } - replaceWithSuggestion(suggestionInfo, spanStart, spanEnd); + replaceWithSuggestion(suggestionInfo); hideWithCleanUp(); } } @@ -3632,8 +3655,7 @@ public class Editor { } private void updateReplaceItem(Menu menu) { - boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions() - && !(mTextView.isInExtractedMode() && mTextView.hasSelection()); + boolean canReplace = mTextView.isSuggestionsEnabled() && shouldOfferToShowSuggestions(); boolean replaceItemExists = menu.findItem(TextView.ID_REPLACE) != null; if (canReplace && !replaceItemExists) { menu.add(Menu.NONE, TextView.ID_REPLACE, MENU_ITEM_ORDER_REPLACE,