From e1fc4f6c3c7d573f013b707ee962d58f9fb636dd Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Mon, 3 Oct 2011 17:01:19 -0700 Subject: [PATCH] Optimisations and bugs in SpellChecker A bug was introduced in a recent refactoring: correct words didn't have their SpellCheckSpan removed, leaving a lot of useless spans. SPAN_EXCLUSIVE_EXCLUSIVE should never have a 0-length. With Japanese characters wordStart could be equal to wordEnd when parsing the text: skip these. Using toString().substring(...) instead of subSequence(...).toString() which is more efficient. Change-Id: I670870a34565939b676400091f4852152a7f7124 --- core/java/android/widget/SpellChecker.java | 9 +++++---- core/java/android/widget/TextView.java | 19 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 772c129a7e643..ce171840dd4ae 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -165,6 +165,7 @@ public class SpellChecker implements SpellCheckerSessionListener { @Override public void onGetSuggestions(SuggestionsInfo[] results) { + final Editable editable = (Editable) mTextView.getText(); for (int i = 0; i < results.length; i++) { SuggestionsInfo suggestionsInfo = results[i]; if (suggestionsInfo.getCookie() != mCookie) continue; @@ -178,18 +179,19 @@ public class SpellChecker implements SpellCheckerSessionListener { boolean looksLikeTypo = ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO) > 0); + SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j]; if (!isInDictionary && looksLikeTypo) { - createMisspelledSuggestionSpan(suggestionsInfo, mSpellCheckSpans[j]); + createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan); } + editable.removeSpan(spellCheckSpan); break; } } } } - private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo, + private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) { - final Editable editable = (Editable) mTextView.getText(); final int start = editable.getSpanStart(spellCheckSpan); final int end = editable.getSpanEnd(spellCheckSpan); @@ -251,6 +253,5 @@ public class SpellChecker implements SpellCheckerSessionListener { // TODO limit to the word rectangle region mTextView.invalidate(); - editable.removeSpan(spellCheckSpan); } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 5edb47cfa647d..3e0650b84228c 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7780,7 +7780,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Iterate over the newly added text and schedule new SpellCheckSpans while (wordStart <= shiftedEnd) { - if (wordEnd >= shiftedStart) { + if (wordEnd >= shiftedStart && wordEnd > wordStart) { // A new word has been created across the interval boundaries. Remove previous spans if (wordStart < shiftedStart && wordEnd > shiftedStart) { removeSpansAt(start, spellCheckSpans, text); @@ -9946,8 +9946,8 @@ 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.subSequence(unionStart, spanStart).toString()); - suggestionInfo.text.append(mText.subSequence(spanEnd, unionEnd).toString()); + suggestionInfo.text.insert(0, mText.toString().substring(unionStart, spanStart)); + suggestionInfo.text.append(mText.toString().substring(spanEnd, unionEnd)); } @Override @@ -9979,7 +9979,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hide(); return; } - final String originalText = mText.subSequence(spanStart, spanEnd).toString(); + final String originalText = mText.toString().substring(spanStart, spanEnd); if (suggestionInfo.suggestionIndex == ADD_TO_DICTIONARY) { Intent intent = new Intent(Settings.ACTION_USER_DICTIONARY_INSERT); @@ -10016,8 +10016,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!TextUtils.isEmpty( suggestionInfo.suggestionSpan.getNotificationTargetClassName())) { InputMethodManager imm = InputMethodManager.peekInstance(); - imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText, - suggestionInfo.suggestionIndex); + if (imm != null) { + imm.notifySuggestionPicked(suggestionInfo.suggestionSpan, originalText, + suggestionInfo.suggestionIndex); + } } // Swap text content between actual text and Suggestion span @@ -10037,7 +10039,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - // Move cursor at the end of the replacement word + // Move cursor at the end of the replaced word Selection.setSelection(editable, spanEnd + lengthDifference); } @@ -10166,8 +10168,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (!hasSelection()) { // There may already be a selection on device rotation - boolean currentWordSelected = selectCurrentWord(); - if (!currentWordSelected) { + if (!selectCurrentWord()) { // No word found under cursor or text selection not permitted. return false; }