summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/widget/SpellChecker.java298
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