From 186aaf973530f426b9b0e602e9744c591aa4aea9 Mon Sep 17 00:00:00 2001 From: Gilles Debunne Date: Fri, 16 Sep 2011 14:26:12 -0700 Subject: [PATCH] Bug 5248215: Even though I turned off the Spelling correction, it still shows up Bug 5313754: SpellCheckSession is released when the window loses focus. When an EditText is initialized with text, a new spell check is initiated and previous spell check spans are removed. Requires a new flag to prevent this from happening when the window focus change comes from the suggestion popup window being shown. Also fixes bug 5329588: handle spell check language change. This change has been reverted. This amended change defers the creation of the SpellChecker, so that it is only created for editable TextView. Patch 3: Bug 5332065, the spell check session is closed in onDetachedFromWindow, which is called when the window is destroyed (like on rotation), which was not the case with onWindowFocusChanged. Patch 5: Fixed life cycle. A view can be created and never attached to the hierarchy. As a result, the spellCheck session would not be closed. Moved spell check to onAttach and perform a spell check when text is changed by setText only if the view has previously been attached (and the spellChecker has been created). Change-Id: Ic2cfbfc0d3f23c589dd9e37f02e4afc1d625615d --- core/java/android/widget/SpellChecker.java | 14 ++++++ core/java/android/widget/TextView.java | 56 ++++++++++++++++------ 2 files changed, 55 insertions(+), 15 deletions(-) diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 14cbf6fe42d5d..6b2f3e4faa19b 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -75,6 +75,20 @@ public class SpellChecker implements SpellCheckerSessionListener { mLength = 0; } + /** + * @return true if a spell checker session has successfully been created. Returns false if not, + * for instance when spell checking has been disabled in settings. + */ + public boolean isSessionActive() { + return mSpellCheckerSession != null; + } + + public void closeSession() { + if (mSpellCheckerSession != null) { + mSpellCheckerSession.close(); + } + } + public void addSpellCheckSpan(SpellCheckSpan spellCheckSpan) { int length = mIds.length; if (mLength >= length) { diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 8db6592a53487..c7695e8d72ca4 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -3250,7 +3250,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener sendOnTextChanged(text, 0, oldlen, textLength); onTextChanged(text, 0, oldlen, textLength); - if (startSpellCheck) { + if (startSpellCheck && mSpellChecker != null) { + // This view has to have been previously attached for mSpellChecker to exist updateSpellCheckSpans(0, textLength); } @@ -4412,6 +4413,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Resolve drawables as the layout direction has been resolved resolveDrawables(); + + updateSpellCheckSpans(0, mText.length()); } @Override @@ -4443,6 +4446,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener hideControllers(); resetResolvedDrawables(); + + if (mSpellChecker != null) { + mSpellChecker.closeSession(); + removeMisspelledSpans(); + // Forces the creation of a new SpellChecker next time this window is created. + // Will handle the cases where the settings has been changed in the meantime. + mSpellChecker = null; + } } @Override @@ -7595,7 +7606,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } ims.mChangedDelta += after-before; } - + sendOnTextChanged(buffer, start, before, after); onTextChanged(buffer, start, before, after); @@ -7737,7 +7748,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * Create new SpellCheckSpans on the modified region. */ private void updateSpellCheckSpans(int start, int end) { - if (!(mText instanceof Editable) || !isSuggestionsEnabled()) return; + if (!isTextEditable() || !isSuggestionsEnabled() || !getSpellChecker().isSessionActive()) + return; Editable text = (Editable) mText; WordIterator wordIterator = getWordIterator(); @@ -8427,13 +8439,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int flags = suggestionSpans[i].getFlags(); if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0 && (flags & SuggestionSpan.FLAG_MISSPELLED) == 0) { - flags = flags & ~SuggestionSpan.FLAG_EASY_CORRECT; + flags &= ~SuggestionSpan.FLAG_EASY_CORRECT; suggestionSpans[i].setFlags(flags); } } } } + /** + * Removes the suggestion spans for misspelled words. + */ + private void removeMisspelledSpans() { + if (mText instanceof Spannable) { + Spannable spannable = (Spannable) mText; + SuggestionSpan[] suggestionSpans = spannable.getSpans(0, + spannable.length(), SuggestionSpan.class); + for (int i = 0; i < suggestionSpans.length; i++) { + int flags = suggestionSpans[i].getFlags(); + if ((flags & SuggestionSpan.FLAG_EASY_CORRECT) != 0 + && (flags & SuggestionSpan.FLAG_MISSPELLED) != 0) { + spannable.removeSpan(suggestionSpans[i]); + } + } + } + } + @Override public boolean onGenericMotionEvent(MotionEvent event) { if (mMovement != null && mText instanceof Spannable && mLayout != null) { @@ -9573,7 +9603,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private final Comparator mSuggestionSpanComparator; private final HashMap mSpansLengths; - private class CustomPopupWindow extends PopupWindow { public CustomPopupWindow(Context context, int defStyle) { super(context, null, defStyle); @@ -9585,9 +9614,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener TextView.this.getPositionListener().removeSubscriber(SuggestionsPopupWindow.this); - if ((mText instanceof Spannable)) { - ((Spannable) mText).removeSpan(mSuggestionRangeSpan); - } + // Safe cast since show() checks that mText is an Editable + ((Spannable) mText).removeSpan(mSuggestionRangeSpan); setCursorVisible(mCursorWasVisibleBeforeSuggestions); if (hasInsertionController()) { @@ -9637,8 +9665,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener void removeMisspelledFlag() { int suggestionSpanFlags = suggestionSpan.getFlags(); if ((suggestionSpanFlags & SuggestionSpan.FLAG_MISSPELLED) > 0) { - suggestionSpanFlags &= ~(SuggestionSpan.FLAG_MISSPELLED); - suggestionSpanFlags &= ~(SuggestionSpan.FLAG_EASY_CORRECT); + suggestionSpanFlags &= ~SuggestionSpan.FLAG_MISSPELLED; + suggestionSpanFlags &= ~SuggestionSpan.FLAG_EASY_CORRECT; suggestionSpan.setFlags(suggestionSpanFlags); } } @@ -10520,9 +10548,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener public abstract int getCurrentCursorOffset(); - protected void updateSelection(int offset) { - updateDrawable(); - } + protected abstract void updateSelection(int offset); public abstract void updatePosition(float x, float y); @@ -10796,8 +10822,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void updateSelection(int offset) { - super.updateSelection(offset); Selection.setSelection((Spannable) mText, offset, getSelectionEnd()); + updateDrawable(); } @Override @@ -10838,8 +10864,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener @Override public void updateSelection(int offset) { - super.updateSelection(offset); Selection.setSelection((Spannable) mText, getSelectionStart(), offset); + updateDrawable(); } @Override