Merge "Fix crash when modifying Selection" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1f2c6dea41
@@ -180,7 +180,7 @@ public class Selection {
|
||||
* Remove the selection or cursor, if any, from the text.
|
||||
*/
|
||||
public static final void removeSelection(Spannable text) {
|
||||
text.removeSpan(SELECTION_START);
|
||||
text.removeSpan(SELECTION_START, Spanned.SPAN_INTERMEDIATE);
|
||||
text.removeSpan(SELECTION_END);
|
||||
removeMemory(text);
|
||||
}
|
||||
|
||||
@@ -45,6 +45,19 @@ extends Spanned
|
||||
*/
|
||||
public void removeSpan(Object what);
|
||||
|
||||
/**
|
||||
* Remove the specified object from the range of text to which it
|
||||
* was attached, if any. It is OK to remove an object that was never
|
||||
* attached in the first place.
|
||||
*
|
||||
* See {@link Spanned} for an explanation of what the flags mean.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
default void removeSpan(Object what, int flags) {
|
||||
removeSpan(what);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory used by TextView to create new {@link Spannable Spannables}. You can subclass
|
||||
* it to provide something other than {@link SpannableString}.
|
||||
|
||||
@@ -312,7 +312,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
||||
// The following condition indicates that the span would become empty
|
||||
(textIsRemoved || mSpanStarts[i] > start || mSpanEnds[i] < mGapStart)) {
|
||||
mIndexOfSpan.remove(mSpans[i]);
|
||||
removeSpan(i);
|
||||
removeSpan(i, 0 /* flags */);
|
||||
return true;
|
||||
}
|
||||
return resolveGap(mSpanStarts[i]) <= end && (i & 1) != 0 &&
|
||||
@@ -472,7 +472,7 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
||||
}
|
||||
|
||||
// Note: caller is responsible for removing the mIndexOfSpan entry.
|
||||
private void removeSpan(int i) {
|
||||
private void removeSpan(int i, int flags) {
|
||||
Object object = mSpans[i];
|
||||
|
||||
int start = mSpanStarts[i];
|
||||
@@ -496,7 +496,9 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
||||
// Invariants must be restored before sending span removed notifications.
|
||||
restoreInvariants();
|
||||
|
||||
sendSpanRemoved(object, start, end);
|
||||
if ((flags & Spanned.SPAN_INTERMEDIATE) == 0) {
|
||||
sendSpanRemoved(object, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
// Documentation from interface
|
||||
@@ -782,10 +784,19 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable
|
||||
* Remove the specified markup object from the buffer.
|
||||
*/
|
||||
public void removeSpan(Object what) {
|
||||
removeSpan(what, 0 /* flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified markup object from the buffer.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void removeSpan(Object what, int flags) {
|
||||
if (mIndexOfSpan == null) return;
|
||||
Integer i = mIndexOfSpan.remove(what);
|
||||
if (i != null) {
|
||||
removeSpan(i.intValue());
|
||||
removeSpan(i.intValue(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -249,6 +249,13 @@ import java.lang.reflect.Array;
|
||||
}
|
||||
|
||||
/* package */ void removeSpan(Object what) {
|
||||
removeSpan(what, 0 /* flags */);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void removeSpan(Object what, int flags) {
|
||||
int count = mSpanCount;
|
||||
Object[] spans = mSpans;
|
||||
int[] data = mSpanData;
|
||||
@@ -262,11 +269,13 @@ import java.lang.reflect.Array;
|
||||
|
||||
System.arraycopy(spans, i + 1, spans, i, c);
|
||||
System.arraycopy(data, (i + 1) * COLUMNS,
|
||||
data, i * COLUMNS, c * COLUMNS);
|
||||
data, i * COLUMNS, c * COLUMNS);
|
||||
|
||||
mSpanCount--;
|
||||
|
||||
sendSpanRemoved(what, ostart, oend);
|
||||
if ((flags & Spanned.SPAN_INTERMEDIATE) == 0) {
|
||||
sendSpanRemoved(what, ostart, oend);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -522,7 +522,7 @@ public class BaseInputConnection implements InputConnection {
|
||||
b = tmp;
|
||||
}
|
||||
|
||||
if (a == b) return null;
|
||||
if (a == b || a < 0) return null;
|
||||
|
||||
if ((flags&GET_TEXT_WITH_STYLES) != 0) {
|
||||
return content.subSequence(a, b);
|
||||
|
||||
@@ -6031,7 +6031,9 @@ public class Editor {
|
||||
mSwitchedLines = false;
|
||||
final int selectionStart = mTextView.getSelectionStart();
|
||||
final int selectionEnd = mTextView.getSelectionEnd();
|
||||
if (selectionStart > selectionEnd) {
|
||||
if (selectionStart < 0 || selectionEnd < 0) {
|
||||
Selection.removeSelection((Spannable) mTextView.getText());
|
||||
} else if (selectionStart > selectionEnd) {
|
||||
Selection.setSelection((Spannable) mTextView.getText(),
|
||||
selectionEnd, selectionStart);
|
||||
}
|
||||
|
||||
@@ -9380,7 +9380,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
|
||||
final int selectionStart = getSelectionStart();
|
||||
final int selectionEnd = getSelectionEnd();
|
||||
|
||||
return selectionStart >= 0 && selectionStart != selectionEnd;
|
||||
return selectionStart >= 0 && selectionEnd > 0 && selectionStart != selectionEnd;
|
||||
}
|
||||
|
||||
String getSelectedText() {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.text;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
@@ -24,6 +26,8 @@ import android.test.MoreAsserts;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
@Presubmit
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
@@ -53,4 +57,34 @@ public abstract class SpannableTest {
|
||||
spans = spannable.getSpans(2, 2, Object.class);
|
||||
MoreAsserts.assertEquals(new Object[]{unemptySpan}, spans);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveSpanWithIntermediateFlag() {
|
||||
Spannable spannable = newSpannableWithText("abcdef");
|
||||
Object emptySpan = new Object();
|
||||
spannable.setSpan(emptySpan, 1, 1, 0);
|
||||
Object unemptySpan = new Object();
|
||||
spannable.setSpan(unemptySpan, 1, 2, 0);
|
||||
|
||||
final CountDownLatch latch = new CountDownLatch(1);
|
||||
SpanWatcher watcher = new SpanWatcher() {
|
||||
@Override
|
||||
public void onSpanAdded(Spannable text, Object what, int start, int end) {}
|
||||
|
||||
@Override
|
||||
public void onSpanRemoved(Spannable text, Object what, int start, int end) {
|
||||
latch.countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpanChanged(Spannable text, Object what, int ostart, int oend, int nstart,
|
||||
int nend) {}
|
||||
};
|
||||
spannable.setSpan(watcher, 0, 2, 0);
|
||||
|
||||
spannable.removeSpan(emptySpan, Spanned.SPAN_INTERMEDIATE);
|
||||
assertEquals(1, latch.getCount());
|
||||
spannable.removeSpan(unemptySpan);
|
||||
assertEquals(0, latch.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user