diff options
| -rw-r--r-- | core/java/android/widget/SpellChecker.java | 298 |
1 files changed, 100 insertions, 198 deletions
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 794b642135d0..d59a415469b6 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -69,9 +69,7 @@ public class SpellChecker implements SpellCheckerSessionListener { private final TextView mTextView; SpellCheckerSession mSpellCheckerSession; - // We assume that the sentence level spell check will always provide better results than words. - // Although word SC has a sequential option. - private boolean mIsSentenceSpellCheckSupported; + final int mCookie; // Paired arrays for the (id, spellCheckSpan) pair. A negative id means the associated @@ -134,7 +132,6 @@ public class SpellChecker implements SpellCheckerSessionListener { | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_TYPO | SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR | SuggestionsInfo.RESULT_ATTR_DONT_SHOW_UI_FOR_SUGGESTIONS); - mIsSentenceSpellCheckSupported = true; } // Restore SpellCheckSpans in pool @@ -318,13 +315,11 @@ public class SpellChecker implements SpellCheckerSessionListener { && WordIterator.isMidWordPunctuation( mCurrentLocale, Character.codePointBefore(editable, end + 1))) { isEditing = false; - } else if (mIsSentenceSpellCheckSupported) { + } else { // Allow the overlap of the cursor and the first boundary of the spell check span // no to skip the spell check of the following word because the // following word will never be spell-checked even if the user finishes composing isEditing = selectionEnd <= start || selectionStart > end; - } else { - isEditing = selectionEnd < start || selectionStart > end; } if (start >= 0 && end > start && (forceCheckWhenEditingWord || isEditing)) { spellCheckSpan.setSpellCheckInProgress(true); @@ -346,13 +341,8 @@ public class SpellChecker implements SpellCheckerSessionListener { textInfos = textInfosCopy; } - if (mIsSentenceSpellCheckSupported) { - mSpellCheckerSession.getSentenceSuggestions( - textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE); - } else { - mSpellCheckerSession.getSuggestions(textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE, - false /* TODO Set sequentialWords to true for initial spell check */); - } + mSpellCheckerSession.getSentenceSuggestions( + textInfos, SuggestionSpan.SUGGESTIONS_MAX_SIZE); } } @@ -381,32 +371,30 @@ public class SpellChecker implements SpellCheckerSessionListener { editable, suggestionsInfo, spellCheckSpan, offset, length); } else { // Valid word -- isInDictionary || !looksLikeTypo - if (mIsSentenceSpellCheckSupported) { - // Allow the spell checker to remove existing misspelled span by - // overwriting the span over the same place - final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan); - final int spellCheckSpanEnd = editable.getSpanEnd(spellCheckSpan); - final int start; - final int end; - if (offset != USE_SPAN_RANGE && length != USE_SPAN_RANGE) { - start = spellCheckSpanStart + offset; - end = start + length; - } else { - start = spellCheckSpanStart; - end = spellCheckSpanEnd; - } - if (spellCheckSpanStart >= 0 && spellCheckSpanEnd > spellCheckSpanStart - && end > start) { - final Long key = Long.valueOf(TextUtils.packRangeInLong(start, end)); - final SuggestionSpan tempSuggestionSpan = mSuggestionSpanCache.get(key); - if (tempSuggestionSpan != null) { - if (DBG) { - Log.i(TAG, "Remove existing misspelled span. " - + editable.subSequence(start, end)); - } - editable.removeSpan(tempSuggestionSpan); - mSuggestionSpanCache.remove(key); + // Allow the spell checker to remove existing misspelled span by + // overwriting the span over the same place + final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan); + final int spellCheckSpanEnd = editable.getSpanEnd(spellCheckSpan); + final int start; + final int end; + if (offset != USE_SPAN_RANGE && length != USE_SPAN_RANGE) { + start = spellCheckSpanStart + offset; + end = start + length; + } else { + start = spellCheckSpanStart; + end = spellCheckSpanEnd; + } + if (spellCheckSpanStart >= 0 && spellCheckSpanEnd > spellCheckSpanStart + && end > start) { + final Long key = Long.valueOf(TextUtils.packRangeInLong(start, end)); + final SuggestionSpan tempSuggestionSpan = mSuggestionSpanCache.get(key); + if (tempSuggestionSpan != null) { + if (DBG) { + Log.i(TAG, "Remove existing misspelled span. " + + editable.subSequence(start, end)); } + editable.removeSpan(tempSuggestionSpan); + mSuggestionSpanCache.remove(key); } } } @@ -531,20 +519,16 @@ public class SpellChecker implements SpellCheckerSessionListener { } SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions, flags); - // TODO: Remove mIsSentenceSpellCheckSupported by extracting an interface - // to share the logic of word level spell checker and sentence level spell checker - if (mIsSentenceSpellCheckSupported) { - final Long key = Long.valueOf(TextUtils.packRangeInLong(start, end)); - final SuggestionSpan tempSuggestionSpan = mSuggestionSpanCache.get(key); - if (tempSuggestionSpan != null) { - if (DBG) { - Log.i(TAG, "Cached span on the same position is cleard. " - + editable.subSequence(start, end)); - } - editable.removeSpan(tempSuggestionSpan); + final Long key = Long.valueOf(TextUtils.packRangeInLong(start, end)); + final SuggestionSpan tempSuggestionSpan = mSuggestionSpanCache.get(key); + if (tempSuggestionSpan != null) { + if (DBG) { + Log.i(TAG, "Cached span on the same position is cleard. " + + editable.subSequence(start, end)); } - mSuggestionSpanCache.put(key, suggestionSpan); + editable.removeSpan(tempSuggestionSpan); } + mSuggestionSpanCache.put(key, suggestionSpan); editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mTextView.invalidateRegion(start, end, false /* No cursor involved */); @@ -599,15 +583,8 @@ public class SpellChecker implements SpellCheckerSessionListener { public void parse() { Editable editable = (Editable) mTextView.getText(); // Iterate over the newly added text and schedule new SpellCheckSpans - final int start; - if (mIsSentenceSpellCheckSupported) { - // TODO: Find the start position of the sentence. - // Set span with the context - start = Math.max( - 0, editable.getSpanStart(mRange) - MIN_SENTENCE_LENGTH); - } else { - start = editable.getSpanStart(mRange); - } + final int start = Math.max( + 0, editable.getSpanStart(mRange) - MIN_SENTENCE_LENGTH); final int end = editable.getSpanEnd(mRange); @@ -633,155 +610,80 @@ public class SpellChecker implements SpellCheckerSessionListener { return; } - // We need to expand by one character because we want to include the spans that - // end/start at position start/end respectively. - SpellCheckSpan[] spellCheckSpans = editable.getSpans(start - 1, end + 1, - SpellCheckSpan.class); - SuggestionSpan[] suggestionSpans = editable.getSpans(start - 1, end + 1, - SuggestionSpan.class); - - int wordCount = 0; boolean scheduleOtherSpellCheck = false; - if (mIsSentenceSpellCheckSupported) { - if (wordIteratorWindowEnd < end) { - if (DBG) { - Log.i(TAG, "schedule other spell check."); - } - // Several batches needed on that region. Cut after last previous word - scheduleOtherSpellCheck = true; - } - int spellCheckEnd = mWordIterator.preceding(wordIteratorWindowEnd); - boolean correct = spellCheckEnd != BreakIterator.DONE; - if (correct) { - spellCheckEnd = mWordIterator.getEnd(spellCheckEnd); - correct = spellCheckEnd != BreakIterator.DONE; + if (wordIteratorWindowEnd < end) { + if (DBG) { + Log.i(TAG, "schedule other spell check."); } - if (!correct) { - if (DBG) { - Log.i(TAG, "Incorrect range span."); - } - stop(); - return; + // Several batches needed on that region. Cut after last previous word + scheduleOtherSpellCheck = true; + } + int spellCheckEnd = mWordIterator.preceding(wordIteratorWindowEnd); + boolean correct = spellCheckEnd != BreakIterator.DONE; + if (correct) { + spellCheckEnd = mWordIterator.getEnd(spellCheckEnd); + correct = spellCheckEnd != BreakIterator.DONE; + } + if (!correct) { + if (DBG) { + Log.i(TAG, "Incorrect range span."); } - do { - // TODO: Find the start position of the sentence. - int spellCheckStart = wordStart; - boolean createSpellCheckSpan = true; - // Cancel or merge overlapped spell check spans - for (int i = 0; i < mLength; ++i) { - final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i]; - if (mIds[i] < 0 || spellCheckSpan.isSpellCheckInProgress()) { - continue; - } - final int spanStart = editable.getSpanStart(spellCheckSpan); - final int spanEnd = editable.getSpanEnd(spellCheckSpan); - if (spanEnd < spellCheckStart || spellCheckEnd < spanStart) { - // No need to merge - continue; - } - if (spanStart <= spellCheckStart && spellCheckEnd <= spanEnd) { - // There is a completely overlapped spell check span - // skip this span - createSpellCheckSpan = false; - if (DBG) { - Log.i(TAG, "The range is overrapped. Skip spell check."); - } - break; - } - // This spellCheckSpan is replaced by the one we are creating - editable.removeSpan(spellCheckSpan); - spellCheckStart = Math.min(spanStart, spellCheckStart); - spellCheckEnd = Math.max(spanEnd, spellCheckEnd); - } - - if (DBG) { - Log.d(TAG, "addSpellCheckSpan: " - + ", End = " + spellCheckEnd + ", Start = " + spellCheckStart - + ", next = " + scheduleOtherSpellCheck + "\n" - + editable.subSequence(spellCheckStart, spellCheckEnd)); + stop(); + return; + } + do { + // TODO: Find the start position of the sentence. + int spellCheckStart = wordStart; + boolean createSpellCheckSpan = true; + // Cancel or merge overlapped spell check spans + for (int i = 0; i < mLength; ++i) { + final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i]; + if (mIds[i] < 0 || spellCheckSpan.isSpellCheckInProgress()) { + continue; } - - // Stop spell checking when there are no characters in the range. - if (spellCheckEnd < start) { - break; + final int spanStart = editable.getSpanStart(spellCheckSpan); + final int spanEnd = editable.getSpanEnd(spellCheckSpan); + if (spanEnd < spellCheckStart || spellCheckEnd < spanStart) { + // No need to merge + continue; } - if (spellCheckEnd <= spellCheckStart) { - Log.w(TAG, "Trying to spellcheck invalid region, from " - + start + " to " + end); + if (spanStart <= spellCheckStart && spellCheckEnd <= spanEnd) { + // There is a completely overlapped spell check span + // skip this span + createSpellCheckSpan = false; + if (DBG) { + Log.i(TAG, "The range is overrapped. Skip spell check."); + } break; } - if (createSpellCheckSpan) { - addSpellCheckSpan(editable, spellCheckStart, spellCheckEnd); - } - } while (false); - wordStart = spellCheckEnd; - } else { - while (wordStart <= end) { - if (wordEnd >= start && wordEnd > wordStart) { - if (wordCount >= MAX_NUMBER_OF_WORDS) { - scheduleOtherSpellCheck = true; - break; - } - // A new word has been created across the interval boundaries with this - // edit. The previous spans (that ended on start / started on end) are - // not valid anymore and must be removed. - if (wordStart < start && wordEnd > start) { - removeSpansAt(editable, start, spellCheckSpans); - removeSpansAt(editable, start, suggestionSpans); - } - - if (wordStart < end && wordEnd > end) { - removeSpansAt(editable, end, spellCheckSpans); - removeSpansAt(editable, end, suggestionSpans); - } - - // Do not create new boundary spans if they already exist - boolean createSpellCheckSpan = true; - if (wordEnd == start) { - for (int i = 0; i < spellCheckSpans.length; i++) { - final int spanEnd = editable.getSpanEnd(spellCheckSpans[i]); - if (spanEnd == start) { - createSpellCheckSpan = false; - break; - } - } - } - - if (wordStart == end) { - for (int i = 0; i < spellCheckSpans.length; i++) { - final int spanStart = editable.getSpanStart(spellCheckSpans[i]); - if (spanStart == end) { - createSpellCheckSpan = false; - break; - } - } - } + // This spellCheckSpan is replaced by the one we are creating + editable.removeSpan(spellCheckSpan); + spellCheckStart = Math.min(spanStart, spellCheckStart); + spellCheckEnd = Math.max(spanEnd, spellCheckEnd); + } - if (createSpellCheckSpan) { - addSpellCheckSpan(editable, wordStart, wordEnd); - } - wordCount++; - } + if (DBG) { + Log.d(TAG, "addSpellCheckSpan: " + + ", End = " + spellCheckEnd + ", Start = " + spellCheckStart + + ", next = " + scheduleOtherSpellCheck + "\n" + + editable.subSequence(spellCheckStart, spellCheckEnd)); + } - // iterate word by word - int originalWordEnd = wordEnd; - wordEnd = mWordIterator.following(wordEnd); - if ((wordIteratorWindowEnd < end) && - (wordEnd == BreakIterator.DONE || wordEnd >= wordIteratorWindowEnd)) { - wordIteratorWindowEnd = - Math.min(end, originalWordEnd + WORD_ITERATOR_INTERVAL); - mWordIterator.setCharSequence( - editable, originalWordEnd, wordIteratorWindowEnd); - wordEnd = mWordIterator.following(originalWordEnd); - } - if (wordEnd == BreakIterator.DONE) break; - wordStart = mWordIterator.getBeginning(wordEnd); - if (wordStart == BreakIterator.DONE) { - break; - } + // Stop spell checking when there are no characters in the range. + if (spellCheckEnd < start) { + break; } - } + if (spellCheckEnd <= spellCheckStart) { + Log.w(TAG, "Trying to spellcheck invalid region, from " + + start + " to " + end); + break; + } + if (createSpellCheckSpan) { + addSpellCheckSpan(editable, spellCheckStart, spellCheckEnd); + } + } while (false); + wordStart = spellCheckEnd; if (scheduleOtherSpellCheck && wordStart != BreakIterator.DONE && wordStart <= end) { // Update range span: start new spell check from last wordStart |