Merge "Bug 5384674: When only one suggestion is returned, it is displayed twice"
This commit is contained in:
committed by
Android (Google) Code Review
commit
6771c7fdbe
@@ -30,8 +30,6 @@ import android.view.textservice.TextServicesManager;
|
|||||||
|
|
||||||
import com.android.internal.util.ArrayUtils;
|
import com.android.internal.util.ArrayUtils;
|
||||||
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper class for TextView. Bridge between the TextView and the Dictionnary service.
|
* Helper class for TextView. Bridge between the TextView and the Dictionnary service.
|
||||||
@@ -167,15 +165,12 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onGetSuggestions(SuggestionsInfo[] results) {
|
public void onGetSuggestions(SuggestionsInfo[] results) {
|
||||||
final Editable editable = (Editable) mTextView.getText();
|
|
||||||
for (int i = 0; i < results.length; i++) {
|
for (int i = 0; i < results.length; i++) {
|
||||||
SuggestionsInfo suggestionsInfo = results[i];
|
SuggestionsInfo suggestionsInfo = results[i];
|
||||||
if (suggestionsInfo.getCookie() != mCookie) continue;
|
if (suggestionsInfo.getCookie() != mCookie) continue;
|
||||||
final int sequenceNumber = suggestionsInfo.getSequence();
|
final int sequenceNumber = suggestionsInfo.getSequence();
|
||||||
|
|
||||||
for (int j = 0; j < mLength; j++) {
|
for (int j = 0; j < mLength; j++) {
|
||||||
final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
|
|
||||||
|
|
||||||
if (sequenceNumber == mIds[j]) {
|
if (sequenceNumber == mIds[j]) {
|
||||||
final int attributes = suggestionsInfo.getSuggestionsAttributes();
|
final int attributes = suggestionsInfo.getSuggestionsAttributes();
|
||||||
boolean isInDictionary =
|
boolean isInDictionary =
|
||||||
@@ -184,31 +179,78 @@ public class SpellChecker implements SpellCheckerSessionListener {
|
|||||||
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
|
((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0);
|
||||||
|
|
||||||
if (!isInDictionary && looksLikeTypo) {
|
if (!isInDictionary && looksLikeTypo) {
|
||||||
String[] suggestions = getSuggestions(suggestionsInfo);
|
createMisspelledSuggestionSpan(suggestionsInfo, mSpellCheckSpans[j]);
|
||||||
SuggestionSpan suggestionSpan = new SuggestionSpan(
|
|
||||||
mTextView.getContext(), suggestions,
|
|
||||||
SuggestionSpan.FLAG_EASY_CORRECT |
|
|
||||||
SuggestionSpan.FLAG_MISSPELLED);
|
|
||||||
final int start = editable.getSpanStart(spellCheckSpan);
|
|
||||||
final int end = editable.getSpanEnd(spellCheckSpan);
|
|
||||||
editable.setSpan(suggestionSpan, start, end,
|
|
||||||
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
|
||||||
// TODO limit to the word rectangle region
|
|
||||||
mTextView.invalidate();
|
|
||||||
}
|
}
|
||||||
editable.removeSpan(spellCheckSpan);
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String[] getSuggestions(SuggestionsInfo suggestionsInfo) {
|
private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo,
|
||||||
// A negative suggestion count is possible
|
SpellCheckSpan spellCheckSpan) {
|
||||||
final int len = Math.max(0, suggestionsInfo.getSuggestionsCount());
|
final Editable editable = (Editable) mTextView.getText();
|
||||||
String[] suggestions = new String[len];
|
final int start = editable.getSpanStart(spellCheckSpan);
|
||||||
for (int j = 0; j < len; j++) {
|
final int end = editable.getSpanEnd(spellCheckSpan);
|
||||||
suggestions[j] = suggestionsInfo.getSuggestionAt(j);
|
|
||||||
|
// Other suggestion spans may exist on that region, with identical suggestions, filter
|
||||||
|
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
|
||||||
|
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) {
|
||||||
|
suggestionSpans[i] = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return suggestions;
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
|
||||||
|
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
|
||||||
|
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||||
|
|
||||||
|
// TODO limit to the word rectangle region
|
||||||
|
mTextView.invalidate();
|
||||||
|
editable.removeSpan(spellCheckSpan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -353,6 +353,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
// Set when this TextView gained focus with some text selected. Will start selection mode.
|
// Set when this TextView gained focus with some text selected. Will start selection mode.
|
||||||
private boolean mCreatedWithASelection = false;
|
private boolean mCreatedWithASelection = false;
|
||||||
|
|
||||||
|
// Size of the window for the word iterator, should be greater than the longest word's length
|
||||||
|
private static final int WORD_ITERATOR_WINDOW_WIDTH = 50;
|
||||||
private WordIterator mWordIterator;
|
private WordIterator mWordIterator;
|
||||||
|
|
||||||
private SpellChecker mSpellChecker;
|
private SpellChecker mSpellChecker;
|
||||||
@@ -2937,11 +2939,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
Spannable sp = new SpannableString(mText);
|
Spannable sp = new SpannableString(mText);
|
||||||
|
|
||||||
for (ChangeWatcher cw :
|
for (ChangeWatcher cw : sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
|
||||||
sp.getSpans(0, sp.length(), ChangeWatcher.class)) {
|
|
||||||
sp.removeSpan(cw);
|
sp.removeSpan(cw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SuggestionSpan[] suggestionSpans = sp.getSpans(0, sp.length(), SuggestionSpan.class);
|
||||||
|
for (int i = 0; i < suggestionSpans.length; i++) {
|
||||||
|
int flags = suggestionSpans[i].getFlags();
|
||||||
|
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
|
||||||
|
&& (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
|
||||||
|
sp.removeSpan(suggestionSpans[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sp.removeSpan(mSuggestionRangeSpan);
|
sp.removeSpan(mSuggestionRangeSpan);
|
||||||
|
|
||||||
ss.text = sp;
|
ss.text = sp;
|
||||||
@@ -4449,7 +4459,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
|
|
||||||
if (mSpellChecker != null) {
|
if (mSpellChecker != null) {
|
||||||
mSpellChecker.closeSession();
|
mSpellChecker.closeSession();
|
||||||
removeMisspelledSpans();
|
|
||||||
// Forces the creation of a new SpellChecker next time this window is created.
|
// Forces the creation of a new SpellChecker next time this window is created.
|
||||||
// Will handle the cases where the settings has been changed in the meantime.
|
// Will handle the cases where the settings has been changed in the meantime.
|
||||||
mSpellChecker = null;
|
mSpellChecker = null;
|
||||||
@@ -8461,24 +8470,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes the suggestion spans for misspelled words.
|
|
||||||
*/
|
|
||||||
private void removeMisspelledSpans() {
|
|
||||||
if (mText instanceof Spannable) {
|
|
||||||
Spannable spannable = (Spannable) mText;
|
|
||||||
SuggestionSpan[] suggestionSpans = spannable.getSpans(0,
|
|
||||||
spannable.length(), SuggestionSpan.class);
|
|
||||||
for (int i = 0; i < suggestionSpans.length; i++) {
|
|
||||||
int flags = suggestionSpans[i].getFlags();
|
|
||||||
if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0
|
|
||||||
&& (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) {
|
|
||||||
spannable.removeSpan(suggestionSpans[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||||
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
|
if (mMovement != null && mText instanceof Spannable && mLayout != null) {
|
||||||
@@ -8959,9 +8950,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
|||||||
mWordIterator = new WordIterator();
|
mWordIterator = new WordIterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
final int TEXT_WINDOW_WIDTH = 50; // Should be larger than the longest word's length
|
final int windowStart = Math.max(0, start - WORD_ITERATOR_WINDOW_WIDTH);
|
||||||
final int windowStart = Math.max(0, start - TEXT_WINDOW_WIDTH);
|
final int windowEnd = Math.min(mText.length(), end + WORD_ITERATOR_WINDOW_WIDTH);
|
||||||
final int windowEnd = Math.min(mText.length(), end + TEXT_WINDOW_WIDTH);
|
|
||||||
mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
|
mWordIterator.setCharSequence(mText.subSequence(windowStart, windowEnd));
|
||||||
|
|
||||||
return windowStart;
|
return windowStart;
|
||||||
|
|||||||
Reference in New Issue
Block a user