Skip to content

Commit 6771c7f

Browse files
Gilles DebunneAndroid (Google) Code Review
authored andcommitted
Merge "Bug 5384674: When only one suggestion is returned, it is displayed twice"
2 parents d3871c5 + 176cd0d commit 6771c7f

File tree

2 files changed

+80
-48
lines changed

2 files changed

+80
-48
lines changed

core/java/android/widget/SpellChecker.java

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@
3030

3131
import com.android.internal.util.ArrayUtils;
3232

33-
import java.util.Locale;
34-
3533

3634
/**
3735
* Helper class for TextView. Bridge between the TextView and the Dictionnary service.
@@ -167,15 +165,12 @@ public void spellCheck() {
167165

168166
@Override
169167
public void onGetSuggestions(SuggestionsInfo[] results) {
170-
final Editable editable = (Editable) mTextView.getText();
171168
for (int i = 0; i < results.length; i++) {
172169
SuggestionsInfo suggestionsInfo = results[i];
173170
if (suggestionsInfo.getCookie() != mCookie) continue;
174171
final int sequenceNumber = suggestionsInfo.getSequence();
175172

176173
for (int j = 0; j < mLength; j++) {
177-
final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
178-
179174
if (sequenceNumber == mIds[j]) {
180175
final int attributes = suggestionsInfo.getSuggestionsAttributes();
181176
boolean isInDictionary =
@@ -184,31 +179,78 @@ public void onGetSuggestions(SuggestionsInfo[] results) {
184179
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
185180

186181
if (!isInDictionary && looksLikeTypo) {
187-
String[] suggestions = getSuggestions(suggestionsInfo);
188-
SuggestionSpan suggestionSpan = new SuggestionSpan(
189-
mTextView.getContext(), suggestions,
190-
SuggestionSpan.FLAG_EASY_CORRECT |
191-
SuggestionSpan.FLAG_MISSPELLED);
192-
final int start = editable.getSpanStart(spellCheckSpan);
193-
final int end = editable.getSpanEnd(spellCheckSpan);
194-
editable.setSpan(suggestionSpan, start, end,
195-
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
196-
// TODO limit to the word rectangle region
197-
mTextView.invalidate();
182+
createMisspelledSuggestionSpan(suggestionsInfo, mSpellCheckSpans[j]);
198183
}
199-
editable.removeSpan(spellCheckSpan);
184+
break;
200185
}
201186
}
202187
}
203188
}
204189

205-
private static String[] getSuggestions(SuggestionsInfo suggestionsInfo) {
206-
// A negative suggestion count is possible
207-
final int len = Math.max(0, suggestionsInfo.getSuggestionsCount());
208-
String[] suggestions = new String[len];
209-
for (int j = 0; j < len; j++) {
210-
suggestions[j] = suggestionsInfo.getSuggestionAt(j);
190+
private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo,
191+
SpellCheckSpan spellCheckSpan) {
192+
final Editable editable = (Editable) mTextView.getText();
193+
final int start = editable.getSpanStart(spellCheckSpan);
194+
final int end = editable.getSpanEnd(spellCheckSpan);
195+
196+
// Other suggestion spans may exist on that region, with identical suggestions, filter
197+
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
198+
SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
199+
final int length = suggestionSpans.length;
200+
for (int i = 0; i < length; i++) {
201+
final int spanStart = editable.getSpanStart(suggestionSpans[i]);
202+
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
203+
if (spanStart != start || spanEnd != end) {
204+
suggestionSpans[i] = null;
205+
break;
206+
}
207+
}
208+
209+
final int suggestionsCount = suggestionsInfo.getSuggestionsCount();
210+
String[] suggestions;
211+
if (suggestionsCount <= 0) {
212+
// A negative suggestion count is possible
213+
suggestions = ArrayUtils.emptyArray(String.class);
214+
} else {
215+
int numberOfSuggestions = 0;
216+
suggestions = new String[suggestionsCount];
217+
218+
for (int i = 0; i < suggestionsCount; i++) {
219+
final String spellSuggestion = suggestionsInfo.getSuggestionAt(i);
220+
if (spellSuggestion == null) break;
221+
boolean suggestionFound = false;
222+
223+
for (int j = 0; j < length && !suggestionFound; j++) {
224+
if (suggestionSpans[j] == null) break;
225+
226+
String[] suggests = suggestionSpans[j].getSuggestions();
227+
for (int k = 0; k < suggests.length; k++) {
228+
if (spellSuggestion.equals(suggests[k])) {
229+
// The suggestion is already provided by an other SuggestionSpan
230+
suggestionFound = true;
231+
break;
232+
}
233+
}
234+
}
235+
236+
if (!suggestionFound) {
237+
suggestions[numberOfSuggestions++] = spellSuggestion;
238+
}
239+
}
240+
241+
if (numberOfSuggestions != suggestionsCount) {
242+
String[] newSuggestions = new String[numberOfSuggestions];
243+
System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions);
244+
suggestions = newSuggestions;
245+
}
211246
}
212-
return suggestions;
247+
248+
SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
249+
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
250+
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
251+
252+
// TODO limit to the word rectangle region
253+
mTextView.invalidate();
254+
editable.removeSpan(spellCheckSpan);
213255
}
214256
}

core/java/android/widget/TextView.java

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ class InputMethodState {
353353
// Set when this TextView gained focus with some text selected. Will start selection mode.
354354
private boolean mCreatedWithASelection = false;
355355

356+
// Size of the window for the word iterator, should be greater than the longest word's length
357+
private static final int WORD_ITERATOR_WINDOW_WIDTH = 50;
356358
private WordIterator mWordIterator;
357359

358360
private SpellChecker mSpellChecker;
@@ -2937,11 +2939,19 @@ public Parcelable onSaveInstanceState() {
29372939

29382940
Spannable sp = new SpannableString(mText);
29392941

2940-
for (ChangeWatcher cw :
2941-
sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
2942+
for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
29422943
sp.removeSpan(cw);
29432944
}
29442945

2946+
SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
2947+
for (int i = 0; i < suggestionSpans.length; i++) {
2948+
int flags = suggestionSpans[i].getFlags();
2949+
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
2950+
&& (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
2951+
sp.removeSpan(suggestionSpans[i]);
2952+
}
2953+
}
2954+
29452955
sp.removeSpan(mSuggestionRangeSpan);
29462956

29472957
ss.text = sp;
@@ -4449,7 +4459,6 @@ protected void onDetachedFromWindow() {
44494459

44504460
if (mSpellChecker != null) {
44514461
mSpellChecker.closeSession();
4452-
removeMisspelledSpans();
44534462
// Forces the creation of a new SpellChecker next time this window is created.
44544463
// Will handle the cases where the settings has been changed in the meantime.
44554464
mSpellChecker = null;
@@ -8461,24 +8470,6 @@ private void downgradeEasyCorrectionSpans() {
84618470
}
84628471
}
84638472

8464-
/**
8465-
* Removes the suggestion spans for misspelled words.
8466-
*/
8467-
private void removeMisspelledSpans() {
8468-
if (mText instanceof Spannable) {
8469-
Spannable spannable = (Spannable) mText;
8470-
SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
8471-
spannable.length(), SuggestionSpan.class);
8472-
for (int i = 0; i < suggestionSpans.length; i++) {
8473-
int flags = suggestionSpans[i].getFlags();
8474-
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
8475-
&& (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
8476-
spannable.removeSpan(suggestionSpans[i]);
8477-
}
8478-
}
8479-
}
8480-
}
8481-
84828473
@Override
84838474
public boolean onGenericMotionEvent(MotionEvent event) {
84848475
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
@@ -8959,9 +8950,8 @@ int prepareWordIterator(int start, int end) {
89598950
mWordIterator = new WordIterator();
89608951
}
89618952

8962-
final int TEXT_WINDOW_WIDTH = 50; // Should be larger than the longest word's length
8963-
final int windowStart = Math.max(0, start - TEXT_WINDOW_WIDTH);
8964-
final int windowEnd = Math.min(mText.length(), end + TEXT_WINDOW_WIDTH);
8953+
final int windowStart = Math.max(0, start - WORD_ITERATOR_WINDOW_WIDTH);
8954+
final int windowEnd = Math.min(mText.length(), end + WORD_ITERATOR_WINDOW_WIDTH);
89658955
mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
89668956

89678957
return windowStart;

0 commit comments

Comments
 (0)