diff --git a/core/java/android/text/style/SuggestionSpan.java b/core/java/android/text/style/SuggestionSpan.java index 0f26a34ece8d5..5dc206fe730b3 100644 --- a/core/java/android/text/style/SuggestionSpan.java +++ b/core/java/android/text/style/SuggestionSpan.java @@ -25,6 +25,7 @@ import android.os.SystemClock; import android.text.ParcelableSpan; import android.text.TextPaint; import android.text.TextUtils; +import android.util.Log; import android.widget.TextView; import java.util.Arrays; @@ -114,7 +115,7 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { * @param context Context for the application * @param locale locale Locale of the suggestions * @param suggestions Suggestions for the string under the span. Only the first up to - * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. + * {@link SuggestionSpan#SUGGESTIONS_MAX_SIZE} will be considered. Null values not permitted. * @param flags Additional flags indicating how this span is handled in TextView * @param notificationTargetClass if not null, this class will get notified when the user * selects one of the suggestions. @@ -124,10 +125,13 @@ public class SuggestionSpan extends CharacterStyle implements ParcelableSpan { final int N = Math.min(SUGGESTIONS_MAX_SIZE, suggestions.length); mSuggestions = Arrays.copyOf(suggestions, N); mFlags = flags; - if (context != null && locale == null) { + if (locale != null) { + mLocaleString = locale.toString(); + } else if (context != null) { mLocaleString = context.getResources().getConfiguration().locale.toString(); } else { - mLocaleString = locale.toString(); + Log.e("SuggestionSpan", "No locale or context specified in SuggestionSpan constructor"); + mLocaleString = ""; } if (notificationTargetClass != null) { diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index a9aec8236716b..570f0f95d6039 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -342,56 +342,15 @@ public class SpellChecker implements SpellCheckerSessionListener { final int end = editable.getSpanEnd(spellCheckSpan); if (start < 0 || end <= start) return; // span was removed in the meantime - // Other suggestion spans may exist on that region, with identical suggestions, filter - // them out to avoid duplicates. - SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class); - final int length = suggestionSpans.length; - for (int i = 0; i < length; i++) { - final int spanStart = editable.getSpanStart(suggestionSpans[i]); - final int spanEnd = editable.getSpanEnd(suggestionSpans[i]); - if (spanStart != start || spanEnd != end) { - // Nulled (to avoid new array allocation) if not on that exact same region - suggestionSpans[i] = null; - } - } - final int suggestionsCount = suggestionsInfo.getSuggestionsCount(); - String[] suggestions; if (suggestionsCount <= 0) { // A negative suggestion count is possible - suggestions = ArrayUtils.emptyArray(String.class); - } else { - int numberOfSuggestions = 0; - suggestions = new String[suggestionsCount]; + return; + } - for (int i = 0; i < suggestionsCount; i++) { - final String spellSuggestion = suggestionsInfo.getSuggestionAt(i); - if (spellSuggestion == null) break; - boolean suggestionFound = false; - - for (int j = 0; j < length && !suggestionFound; j++) { - if (suggestionSpans[j] == null) break; - - String[] suggests = suggestionSpans[j].getSuggestions(); - for (int k = 0; k < suggests.length; k++) { - if (spellSuggestion.equals(suggests[k])) { - // The suggestion is already provided by an other SuggestionSpan - suggestionFound = true; - break; - } - } - } - - if (!suggestionFound) { - suggestions[numberOfSuggestions++] = spellSuggestion; - } - } - - if (numberOfSuggestions != suggestionsCount) { - String[] newSuggestions = new String[numberOfSuggestions]; - System.arraycopy(suggestions, 0, newSuggestions, 0, numberOfSuggestions); - suggestions = newSuggestions; - } + String[] suggestions = new String[suggestionsCount]; + for (int i = 0; i < suggestionsCount; i++) { + suggestions[i] = suggestionsInfo.getSuggestionAt(i); } SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions, diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 9fb26ae7455d9..4caed562db040 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -9838,17 +9838,34 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener String[] suggestions = suggestionSpan.getSuggestions(); int nbSuggestions = suggestions.length; for (int suggestionIndex = 0; suggestionIndex < nbSuggestions; suggestionIndex++) { - SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions]; - suggestionInfo.suggestionSpan = suggestionSpan; - suggestionInfo.suggestionIndex = suggestionIndex; - suggestionInfo.text.replace(0, suggestionInfo.text.length(), - suggestions[suggestionIndex]); + String suggestion = suggestions[suggestionIndex]; - mNumberOfSuggestions++; - if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) { - // Also end outer for loop - spanIndex = nbSpans; - break; + boolean suggestionIsDuplicate = false; + for (int i = 0; i < mNumberOfSuggestions; i++) { + if (mSuggestionInfos[i].text.toString().equals(suggestion)) { + SuggestionSpan otherSuggestionSpan = mSuggestionInfos[i].suggestionSpan; + final int otherSpanStart = spannable.getSpanStart(otherSuggestionSpan); + final int otherSpanEnd = spannable.getSpanEnd(otherSuggestionSpan); + if (spanStart == otherSpanStart && spanEnd == otherSpanEnd) { + suggestionIsDuplicate = true; + break; + } + } + } + + if (!suggestionIsDuplicate) { + SuggestionInfo suggestionInfo = mSuggestionInfos[mNumberOfSuggestions]; + suggestionInfo.suggestionSpan = suggestionSpan; + suggestionInfo.suggestionIndex = suggestionIndex; + suggestionInfo.text.replace(0, suggestionInfo.text.length(), suggestion); + + mNumberOfSuggestions++; + + if (mNumberOfSuggestions == MAX_NUMBER_SUGGESTIONS) { + // Also end outer for loop + spanIndex = nbSpans; + break; + } } } } @@ -9857,7 +9874,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener highlightTextDifferences(mSuggestionInfos[i], spanUnionStart, spanUnionEnd); } - // Add to dictionary item if there is a span with the misspelled flag + // Add "Add to dictionary" item if there is a span with the misspelled flag if (misspelledSpan != null) { final int misspelledStart = spannable.getSpanStart(misspelledSpan); final int misspelledEnd = spannable.getSpanEnd(misspelledSpan); @@ -9915,8 +9932,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); // Add the text before and after the span. - suggestionInfo.text.insert(0, mText.toString().substring(unionStart, spanStart)); - suggestionInfo.text.append(mText.toString().substring(spanEnd, unionEnd)); + final String textAsString = text.toString(); + suggestionInfo.text.insert(0, textAsString.substring(unionStart, spanStart)); + suggestionInfo.text.append(textAsString.substring(spanEnd, unionEnd)); } @Override