@@ -428,6 +428,12 @@ public SpannableStringBuilder replace(final int start, final int end,
428428 final int origLen = end - start ;
429429 final int newLen = tbend - tbstart ;
430430
431+ if (origLen == 0 && newLen == 0 && !hasNonExclusiveExclusiveSpanAt (tb , tbstart )) {
432+ // This is a no-op iif there are no spans in tb that would be added (with a 0-length)
433+ // Early exit so that the text watchers do not get notified
434+ return this ;
435+ }
436+
431437 TextWatcher [] textWatchers = getSpans (start , start + origLen , TextWatcher .class );
432438 sendBeforeTextChanged (textWatchers , start , origLen , newLen );
433439
@@ -470,6 +476,20 @@ public SpannableStringBuilder replace(final int start, final int end,
470476 return this ;
471477 }
472478
479+ private static boolean hasNonExclusiveExclusiveSpanAt (CharSequence text , int offset ) {
480+ if (text instanceof Spanned ) {
481+ Spanned spanned = (Spanned ) text ;
482+ Object [] spans = spanned .getSpans (offset , offset , Object .class );
483+ final int length = spans .length ;
484+ for (int i = 0 ; i < length ; i ++) {
485+ Object span = spans [i ];
486+ int flags = spanned .getSpanFlags (span );
487+ if (flags != Spanned .SPAN_EXCLUSIVE_EXCLUSIVE ) return true ;
488+ }
489+ }
490+ return false ;
491+ }
492+
473493 private void sendToSpanWatchers (int replaceStart , int replaceEnd , int nbNewChars ) {
474494 for (int i = 0 ; i < mSpanCountBeforeAdd ; i ++) {
475495 int spanStart = mSpanStarts [i ];
0 commit comments