Skip to content

Commit 737f330

Browse files
Gilles DebunneAndroid (Google) Code Review
authored andcommitted
Merge "Bug 5437846: Crash in SpellChecker"
2 parents 8c3e707 + f656030 commit 737f330

File tree

1 file changed

+46
-41
lines changed

1 file changed

+46
-41
lines changed

core/java/android/widget/SpellChecker.java

Lines changed: 46 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ public class SpellChecker implements SpellCheckerSessionListener {
4444
private final static int MAX_SPELL_BATCH_SIZE = 50;
4545

4646
private final TextView mTextView;
47-
private final Editable mText;
4847

4948
final SpellCheckerSession mSpellCheckerSession;
5049
final int mCookie;
@@ -64,7 +63,6 @@ public class SpellChecker implements SpellCheckerSessionListener {
6463

6564
public SpellChecker(TextView textView) {
6665
mTextView = textView;
67-
mText = (Editable) textView.getText();
6866

6967
final TextServicesManager textServicesManager = (TextServicesManager) textView.getContext().
7068
getSystemService(Context.TEXT_SERVICES_MANAGER_SERVICE);
@@ -121,9 +119,9 @@ private int nextSpellCheckSpanIndex() {
121119
return mLength - 1;
122120
}
123121

124-
private void addSpellCheckSpan(int start, int end) {
122+
private void addSpellCheckSpan(Editable editable, int start, int end) {
125123
final int index = nextSpellCheckSpanIndex();
126-
mText.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
124+
editable.setSpan(mSpellCheckSpans[index], start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
127125
mIds[index] = mSpanSequenceCounter++;
128126
}
129127

@@ -168,8 +166,9 @@ public void spellCheck(int start, int end) {
168166
private void spellCheck() {
169167
if (mSpellCheckerSession == null) return;
170168

171-
final int selectionStart = Selection.getSelectionStart(mText);
172-
final int selectionEnd = Selection.getSelectionEnd(mText);
169+
Editable editable = (Editable) mTextView.getText();
170+
final int selectionStart = Selection.getSelectionStart(editable);
171+
final int selectionEnd = Selection.getSelectionEnd(editable);
173172

174173
TextInfo[] textInfos = new TextInfo[mLength];
175174
int textInfosCount = 0;
@@ -178,12 +177,12 @@ private void spellCheck() {
178177
final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[i];
179178
if (spellCheckSpan.isSpellCheckInProgress()) continue;
180179

181-
final int start = mText.getSpanStart(spellCheckSpan);
182-
final int end = mText.getSpanEnd(spellCheckSpan);
180+
final int start = editable.getSpanStart(spellCheckSpan);
181+
final int end = editable.getSpanEnd(spellCheckSpan);
183182

184183
// Do not check this word if the user is currently editing it
185184
if (start >= 0 && end > start && (selectionEnd < start || selectionStart > end)) {
186-
final String word = mText.subSequence(start, end).toString();
185+
final String word = editable.subSequence(start, end).toString();
187186
spellCheckSpan.setSpellCheckInProgress(true);
188187
textInfos[textInfosCount++] = new TextInfo(word, mCookie, mIds[i]);
189188
}
@@ -202,6 +201,8 @@ private void spellCheck() {
202201

203202
@Override
204203
public void onGetSuggestions(SuggestionsInfo[] results) {
204+
Editable editable = (Editable) mTextView.getText();
205+
205206
for (int i = 0; i < results.length; i++) {
206207
SuggestionsInfo suggestionsInfo = results[i];
207208
if (suggestionsInfo.getCookie() != mCookie) continue;
@@ -217,9 +218,9 @@ public void onGetSuggestions(SuggestionsInfo[] results) {
217218

218219
SpellCheckSpan spellCheckSpan = mSpellCheckSpans[j];
219220
if (!isInDictionary && looksLikeTypo) {
220-
createMisspelledSuggestionSpan(suggestionsInfo, spellCheckSpan);
221+
createMisspelledSuggestionSpan(editable, suggestionsInfo, spellCheckSpan);
221222
}
222-
mText.removeSpan(spellCheckSpan);
223+
editable.removeSpan(spellCheckSpan);
223224
break;
224225
}
225226
}
@@ -234,18 +235,18 @@ public void onGetSuggestions(SuggestionsInfo[] results) {
234235
}
235236
}
236237

237-
private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo,
238-
SpellCheckSpan spellCheckSpan) {
239-
final int start = mText.getSpanStart(spellCheckSpan);
240-
final int end = mText.getSpanEnd(spellCheckSpan);
238+
private void createMisspelledSuggestionSpan(Editable editable,
239+
SuggestionsInfo suggestionsInfo, SpellCheckSpan spellCheckSpan) {
240+
final int start = editable.getSpanStart(spellCheckSpan);
241+
final int end = editable.getSpanEnd(spellCheckSpan);
241242

242243
// Other suggestion spans may exist on that region, with identical suggestions, filter
243244
// them out to avoid duplicates. First, filter suggestion spans on that exact region.
244-
SuggestionSpan[] suggestionSpans = mText.getSpans(start, end, SuggestionSpan.class);
245+
SuggestionSpan[] suggestionSpans = editable.getSpans(start, end, SuggestionSpan.class);
245246
final int length = suggestionSpans.length;
246247
for (int i = 0; i < length; i++) {
247-
final int spanStart = mText.getSpanStart(suggestionSpans[i]);
248-
final int spanEnd = mText.getSpanEnd(suggestionSpans[i]);
248+
final int spanStart = editable.getSpanStart(suggestionSpans[i]);
249+
final int spanEnd = editable.getSpanEnd(suggestionSpans[i]);
249250
if (spanStart != start || spanEnd != end) {
250251
suggestionSpans[i] = null;
251252
break;
@@ -293,7 +294,7 @@ private void createMisspelledSuggestionSpan(SuggestionsInfo suggestionsInfo,
293294

294295
SuggestionSpan suggestionSpan = new SuggestionSpan(mTextView.getContext(), suggestions,
295296
SuggestionSpan.FLAG_EASY_CORRECT | SuggestionSpan.FLAG_MISSPELLED);
296-
mText.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
297+
editable.setSpan(suggestionSpan, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
297298

298299
// TODO limit to the word rectangle region
299300
mTextView.invalidate();
@@ -304,22 +305,24 @@ private class SpellParser {
304305
private Object mRange = new Object();
305306

306307
public void init(int start, int end) {
307-
mText.setSpan(mRange, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
308+
((Editable) mTextView.getText()).setSpan(mRange, start, end,
309+
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
308310
}
309311

310312
public void close() {
311-
mText.removeSpan(mRange);
313+
((Editable) mTextView.getText()).removeSpan(mRange);
312314
}
313315

314316
public boolean isDone() {
315-
return mText.getSpanStart(mRange) < 0;
317+
return ((Editable) mTextView.getText()).getSpanStart(mRange) < 0;
316318
}
317319

318320
public void parse() {
321+
Editable editable = (Editable) mTextView.getText();
319322
// Iterate over the newly added text and schedule new SpellCheckSpans
320-
final int start = mText.getSpanStart(mRange);
321-
final int end = mText.getSpanEnd(mRange);
322-
mWordIterator.setCharSequence(mText, start, end);
323+
final int start = editable.getSpanStart(mRange);
324+
final int end = editable.getSpanEnd(mRange);
325+
mWordIterator.setCharSequence(editable, start, end);
323326

324327
// Move back to the beginning of the current word, if any
325328
int wordStart = mWordIterator.preceding(start);
@@ -333,14 +336,16 @@ public void parse() {
333336
wordEnd = mWordIterator.getEnd(wordStart);
334337
}
335338
if (wordEnd == BreakIterator.DONE) {
336-
mText.removeSpan(mRange);
339+
editable.removeSpan(mRange);
337340
return;
338341
}
339342

340343
// We need to expand by one character because we want to include the spans that
341344
// end/start at position start/end respectively.
342-
SpellCheckSpan[] spellCheckSpans = mText.getSpans(start-1, end+1, SpellCheckSpan.class);
343-
SuggestionSpan[] suggestionSpans = mText.getSpans(start-1, end+1, SuggestionSpan.class);
345+
SpellCheckSpan[] spellCheckSpans = editable.getSpans(start - 1, end + 1,
346+
SpellCheckSpan.class);
347+
SuggestionSpan[] suggestionSpans = editable.getSpans(start - 1, end + 1,
348+
SuggestionSpan.class);
344349

345350
int nbWordsChecked = 0;
346351
boolean scheduleOtherSpellCheck = false;
@@ -350,20 +355,20 @@ public void parse() {
350355
// A new word has been created across the interval boundaries with this edit.
351356
// Previous spans (ended on start / started on end) removed, not valid anymore
352357
if (wordStart < start && wordEnd > start) {
353-
removeSpansAt(start, spellCheckSpans);
354-
removeSpansAt(start, suggestionSpans);
358+
removeSpansAt(editable, start, spellCheckSpans);
359+
removeSpansAt(editable, start, suggestionSpans);
355360
}
356361

357362
if (wordStart < end && wordEnd > end) {
358-
removeSpansAt(end, spellCheckSpans);
359-
removeSpansAt(end, suggestionSpans);
363+
removeSpansAt(editable, end, spellCheckSpans);
364+
removeSpansAt(editable, end, suggestionSpans);
360365
}
361366

362367
// Do not create new boundary spans if they already exist
363368
boolean createSpellCheckSpan = true;
364369
if (wordEnd == start) {
365370
for (int i = 0; i < spellCheckSpans.length; i++) {
366-
final int spanEnd = mText.getSpanEnd(spellCheckSpans[i]);
371+
final int spanEnd = editable.getSpanEnd(spellCheckSpans[i]);
367372
if (spanEnd == start) {
368373
createSpellCheckSpan = false;
369374
break;
@@ -373,7 +378,7 @@ public void parse() {
373378

374379
if (wordStart == end) {
375380
for (int i = 0; i < spellCheckSpans.length; i++) {
376-
final int spanStart = mText.getSpanStart(spellCheckSpans[i]);
381+
final int spanStart = editable.getSpanStart(spellCheckSpans[i]);
377382
if (spanStart == end) {
378383
createSpellCheckSpan = false;
379384
break;
@@ -386,7 +391,7 @@ public void parse() {
386391
scheduleOtherSpellCheck = true;
387392
break;
388393
}
389-
addSpellCheckSpan(wordStart, wordEnd);
394+
addSpellCheckSpan(editable, wordStart, wordEnd);
390395
nbWordsChecked++;
391396
}
392397
}
@@ -401,23 +406,23 @@ public void parse() {
401406
}
402407

403408
if (scheduleOtherSpellCheck) {
404-
mText.setSpan(mRange, wordStart, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
409+
editable.setSpan(mRange, wordStart, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
405410
} else {
406-
mText.removeSpan(mRange);
411+
editable.removeSpan(mRange);
407412
}
408413

409414
spellCheck();
410415
}
411416

412-
private <T> void removeSpansAt(int offset, T[] spans) {
417+
private <T> void removeSpansAt(Editable editable, int offset, T[] spans) {
413418
final int length = spans.length;
414419
for (int i = 0; i < length; i++) {
415420
final T span = spans[i];
416-
final int start = mText.getSpanStart(span);
421+
final int start = editable.getSpanStart(span);
417422
if (start > offset) continue;
418-
final int end = mText.getSpanEnd(span);
423+
final int end = editable.getSpanEnd(span);
419424
if (end < offset) continue;
420-
mText.removeSpan(span);
425+
editable.removeSpan(span);
421426
}
422427
}
423428
}

0 commit comments

Comments
 (0)