Loading core/java/android/widget/Editor.java +4 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading core/java/android/widget/SpellChecker.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; } } core/java/android/widget/TextView.java +23 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading
core/java/android/widget/Editor.java +4 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading
core/java/android/widget/SpellChecker.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; } }
core/java/android/widget/TextView.java +23 −8 Original line number Diff line number Diff line Loading @@ -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. Loading