resolved conflicts for merge of 1742f20c to master
Change-Id: I02d84edfe8cc0b71881884ecec21f831404aa555
diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 31da5b5..6700829 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -45,14 +45,15 @@
// No more than this number of words will be parsed on each iteration to ensure a minimum
// lock of the UI thread
- public static final int MAX_NUMBER_OF_WORDS = 10;
+ public static final int MAX_NUMBER_OF_WORDS = 50;
- // Safe estimate, will ensure that the interval below usually does not have to be updated
- public static final int AVERAGE_WORD_LENGTH = 10;
+ // Rough estimate, such that the word iterator interval usually does not need to be shifted
+ public static final int AVERAGE_WORD_LENGTH = 7;
// When parsing, use a character window of that size. Will be shifted if needed
public static final int WORD_ITERATOR_INTERVAL = AVERAGE_WORD_LENGTH * MAX_NUMBER_OF_WORDS;
+ // Pause between each spell check to keep the UI smooth
private final static int SPELL_PAUSE_DURATION = 400; // milliseconds
private final TextView mTextView;
@@ -75,6 +76,14 @@
private Locale mCurrentLocale;
+ // Shared by all SpellParsers. Cannot be shared with TextView since it may be used
+ // concurrently due to the asynchronous nature of onGetSuggestions.
+ private WordIterator mWordIterator;
+
+ private TextServicesManager mTextServicesManager;
+
+ private Runnable mSpellRunnable;
+
public SpellChecker(TextView textView) {
mTextView = textView;
@@ -136,6 +145,10 @@
for (int i = 0; i < length; i++) {
mSpellParsers[i].stop();
}
+
+ if (mSpellRunnable != null) {
+ mTextView.removeCallbacks(mSpellRunnable);
+ }
}
private int nextSpellCheckSpanIndex() {
@@ -285,18 +298,29 @@
}
}
- mTextView.postDelayed(new Runnable() {
- @Override
- public void run() {
- final int length = mSpellParsers.length;
- for (int i = 0; i < length; i++) {
- final SpellParser spellParser = mSpellParsers[i];
- if (spellParser.isParsing()) {
- spellParser.parse();
+ scheduleNewSpellCheck();
+ }
+
+ private void scheduleNewSpellCheck() {
+ if (mSpellRunnable == null) {
+ mSpellRunnable = new Runnable() {
+ @Override
+ public void run() {
+ final int length = mSpellParsers.length;
+ for (int i = 0; i < length; i++) {
+ final SpellParser spellParser = mSpellParsers[i];
+ if (!spellParser.isFinished()) {
+ spellParser.parse();
+ break; // run one spell parser at a time to bound running time
+ }
}
}
- }
- }, SPELL_PAUSE_DURATION);
+ };
+ } else {
+ mTextView.removeCallbacks(mSpellRunnable);
+ }
+
+ mTextView.postDelayed(mSpellRunnable, SPELL_PAUSE_DURATION);
}
private void createMisspelledSuggestionSpan(Editable editable, SuggestionsInfo suggestionsInfo,
@@ -393,20 +417,19 @@
final int start = editable.getSpanStart(mRange);
final int end = editable.getSpanEnd(mRange);
- final WordIterator wordIterator = mTextView.getWordIterator();
int wordIteratorWindowEnd = Math.min(end, start + WORD_ITERATOR_INTERVAL);
- wordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
+ mWordIterator.setCharSequence(editable, start, wordIteratorWindowEnd);
// Move back to the beginning of the current word, if any
- int wordStart = wordIterator.preceding(start);
+ int wordStart = mWordIterator.preceding(start);
int wordEnd;
if (wordStart == BreakIterator.DONE) {
- wordEnd = wordIterator.following(start);
+ wordEnd = mWordIterator.following(start);
if (wordEnd != BreakIterator.DONE) {
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
}
} else {
- wordEnd = wordIterator.getEnd(wordStart);
+ wordEnd = mWordIterator.getEnd(wordStart);
}
if (wordEnd == BreakIterator.DONE) {
removeRangeSpan(editable);
@@ -472,15 +495,15 @@
// iterate word by word
int originalWordEnd = wordEnd;
- wordEnd = wordIterator.following(wordEnd);
+ wordEnd = mWordIterator.following(wordEnd);
if ((wordIteratorWindowEnd < end) &&
(wordEnd == BreakIterator.DONE || wordEnd >= wordIteratorWindowEnd)) {
wordIteratorWindowEnd = Math.min(end, originalWordEnd + WORD_ITERATOR_INTERVAL);
- wordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
- wordEnd = wordIterator.following(originalWordEnd);
+ mWordIterator.setCharSequence(editable, originalWordEnd, wordIteratorWindowEnd);
+ wordEnd = mWordIterator.following(originalWordEnd);
}
if (wordEnd == BreakIterator.DONE) break;
- wordStart = wordIterator.getBeginning(wordEnd);
+ wordStart = mWordIterator.getBeginning(wordEnd);
if (wordStart == BreakIterator.DONE) {
break;
}