diff options
| -rw-r--r-- | core/java/android/widget/Editor.java | 4 | ||||
| -rw-r--r-- | core/java/android/widget/SpellChecker.java | 35 | ||||
| -rw-r--r-- | core/java/android/widget/TextView.java | 31 |
3 files changed, 62 insertions, 8 deletions
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 91c989dd8615..50d28abc25ad 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -499,6 +499,10 @@ public class Editor { * Create new SpellCheckSpans on the modified region. */ private void updateSpellCheckSpans(int start, int end, boolean createSpellChecker) { + // Remove spans whose adjacent characters are text not punctuation + mTextView.removeAdjacentSuggestionSpans(start); + mTextView.removeAdjacentSuggestionSpans(end); + if (mTextView.isTextEditable() && mTextView.isSuggestionsEnabled() && !(mTextView instanceof ExtractEditText)) { if (mSpellChecker == null && createSpellChecker) { diff --git a/core/java/android/widget/SpellChecker.java b/core/java/android/widget/SpellChecker.java index 9e7f97ea16eb..b204dfd0c032 100644 --- a/core/java/android/widget/SpellChecker.java +++ b/core/java/android/widget/SpellChecker.java @@ -753,4 +753,39 @@ public class SpellChecker implements SpellCheckerSessionListener { } } } + + public static boolean haveWordBoundariesChanged(final Editable editable, final int start, + final int end, final int spanStart, final int spanEnd) { + final boolean haveWordBoundariesChanged; + if (spanEnd != start && spanStart != end) { + haveWordBoundariesChanged = true; + if (DBG) { + Log.d(TAG, "(1) Text inside the span has been modified. Remove."); + } + } else if (spanEnd == start && start < editable.length()) { + final int codePoint = Character.codePointAt(editable, start); + haveWordBoundariesChanged = Character.isLetterOrDigit(codePoint); + if (DBG) { + Log.d(TAG, "(2) Characters have been appended to the spanned text. " + + (haveWordBoundariesChanged ? "Remove.<" : "Keep. <") + (char)(codePoint) + + ">, " + editable + ", " + editable.subSequence(spanStart, spanEnd) + ", " + + start); + } + } else if (spanStart == end && end > 0) { + final int codePoint = Character.codePointBefore(editable, end); + haveWordBoundariesChanged = Character.isLetterOrDigit(codePoint); + if (DBG) { + Log.d(TAG, "(3) Characters have been prepended to the spanned text. " + + (haveWordBoundariesChanged ? "Remove.<" : "Keep.<") + (char)(codePoint) + + ">, " + editable + ", " + editable.subSequence(spanStart, spanEnd) + ", " + + end); + } + } else { + if (DBG) { + Log.d(TAG, "(4) Characters adjacent to the spanned text were deleted. Keep."); + } + haveWordBoundariesChanged = false; + } + return haveWordBoundariesChanged; + } } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 71baa9004680..816bb18dcd56 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -7362,27 +7362,42 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // The spans that are inside or intersect the modified region no longer make sense - removeIntersectingSpans(start, start + before, SpellCheckSpan.class); - removeIntersectingSpans(start, start + before, SuggestionSpan.class); + removeIntersectingNonAdjacentSpans(start, start + before, SpellCheckSpan.class); + removeIntersectingNonAdjacentSpans(start, start + before, SuggestionSpan.class); } // Removes all spans that are inside or actually overlap the start..end range - private <T> void removeIntersectingSpans(int start, int end, Class<T> type) { + private <T> void removeIntersectingNonAdjacentSpans(int start, int end, Class<T> type) { if (!(mText instanceof Editable)) return; Editable text = (Editable) mText; T[] spans = text.getSpans(start, end, type); final int length = spans.length; for (int i = 0; i < length; i++) { - final int s = text.getSpanStart(spans[i]); - final int e = text.getSpanEnd(spans[i]); - // Spans that are adjacent to the edited region will be handled in - // updateSpellCheckSpans. Result depends on what will be added (space or text) - if (e == start || s == end) break; + final int spanStart = text.getSpanStart(spans[i]); + final int spanEnd = text.getSpanEnd(spans[i]); + if (spanEnd == start || spanStart == end) break; text.removeSpan(spans[i]); } } + void removeAdjacentSuggestionSpans(final int pos) { + if (!(mText instanceof Editable)) return; + final Editable text = (Editable) mText; + + final SuggestionSpan[] spans = text.getSpans(pos, pos, SuggestionSpan.class); + final int length = spans.length; + for (int i = 0; i < length; i++) { + final int spanStart = text.getSpanStart(spans[i]); + final int spanEnd = text.getSpanEnd(spans[i]); + if (spanEnd == pos || spanStart == pos) { + if (SpellChecker.haveWordBoundariesChanged(text, pos, pos, spanStart, spanEnd)) { + text.removeSpan(spans[i]); + } + } + } + } + /** * Not private so it can be called from an inner class without going * through a thunk. |