ClassCastException fix: getText() returns CharSequence not Spanned.

Summary:
ClassCastException fix: getText() returns CharSequence not Spanned.
From the other hand, EditTexts getText method returns Editable which extends Spanned.
This commit fixes two similar bugs one in flat TextView and another in standard TextView.
Also, it removes redundant checks in the ReactEditText.

Application without this change sporadically crashes with the following stack trace:
```
java.lang.ClassCastException: java.lang.String cannot be cast to android.text.Spanned
	at com.facebook.react.views.text.ReactTextView.reactTagForTouch(ReactTextView.java:195)
	at com.facebook.react.uimanager.TouchTargetHelper.getTouchTargetForView(TouchTargetHelper.java:269)
	at com.facebook.react.uimanager.TouchTargetHelper.findTargetTagAndCoordinatesForTouch$58866680(TouchTargetHelper.java:101)
	at com.facebook.react.uimanager.JSTouchDispatcher.handleTouchEvent(JSTouchDispatcher.java:77)
	at com.facebook.react.ReactRootView.dispatchJSTouchEvent(ReactRootView.java:151)
	at com.facebook.react.ReactRootView.onInterceptTouchEvent(ReactRootView.java:127)
	at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:2110)

```
Closes https://github.com/facebook/react-native/pull/15452

Differential Revision: D6775986

Pulled By: hramos

fbshipit-source-id: 6de929937cbbb3e7bd98a708a40700f883cbaef0
This commit is contained in:
Sergei Dryganets 2018-01-22 14:46:42 -08:00 committed by Facebook Github Bot
parent f5975a97ad
commit 46cc4907e3
3 changed files with 26 additions and 22 deletions

View File

@ -70,11 +70,14 @@ import android.text.Spanned;
}
if (mLayout != null) {
Spanned text = (Spanned) mLayout.getText();
RCTRawText[] spans = text.getSpans(0, text.length(), RCTRawText.class);
for (RCTRawText span : spans) {
if (span.getReactTag() == tag) {
return true;
CharSequence text = mLayout.getText();
if (text instanceof Spanned) {
Spanned spannedText = (Spanned) text;
RCTRawText[] spans = spannedText.getSpans(0, text.length(), RCTRawText.class);
for (RCTRawText span : spans) {
if (span.getReactTag() == tag) {
return true;
}
}
}
}

View File

@ -76,7 +76,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
@Override
public int reactTagForTouch(float touchX, float touchY) {
Spanned text = (Spanned) getText();
CharSequence text = getText();
int target = getId();
int x = (int) touchX;
@ -94,20 +94,21 @@ public class ReactTextView extends TextView implements ReactCompoundView {
int lineEndX = (int) layout.getLineRight(line);
// TODO(5966918): Consider extending touchable area for text spans by some DP constant
if (x >= lineStartX && x <= lineEndX) {
if (text instanceof Spanned && x >= lineStartX && x <= lineEndX) {
Spanned spannedText = (Spanned) text;
int index = layout.getOffsetForHorizontal(line, x);
// We choose the most inner span (shortest) containing character at the given index
// if no such span can be found we will send the textview's react id as a touch handler
// In case when there are more than one spans with same length we choose the last one
// from the spans[] array, since it correspond to the most inner react element
ReactTagSpan[] spans = text.getSpans(index, index, ReactTagSpan.class);
ReactTagSpan[] spans = spannedText.getSpans(index, index, ReactTagSpan.class);
if (spans != null) {
int targetSpanTextLength = text.length();
for (int i = 0; i < spans.length; i++) {
int spanStart = text.getSpanStart(spans[i]);
int spanEnd = text.getSpanEnd(spans[i]);
int spanStart = spannedText.getSpanStart(spans[i]);
int spanEnd = spannedText.getSpanEnd(spans[i]);
if (spanEnd > index && (spanEnd - spanStart) <= targetSpanTextLength) {
target = spans[i].getReactTag();
targetSpanTextLength = (spanEnd - spanStart);

View File

@ -525,8 +525,8 @@ public class ReactEditText extends EditText {
@Override
protected boolean verifyDrawable(Drawable drawable) {
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
if (span.getDrawable() == drawable) {
@ -539,8 +539,8 @@ public class ReactEditText extends EditText {
@Override
public void invalidateDrawable(Drawable drawable) {
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
if (span.getDrawable() == drawable) {
@ -554,8 +554,8 @@ public class ReactEditText extends EditText {
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
span.onDetachedFromWindow();
@ -566,8 +566,8 @@ public class ReactEditText extends EditText {
@Override
public void onStartTemporaryDetach() {
super.onStartTemporaryDetach();
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
span.onStartTemporaryDetach();
@ -578,8 +578,8 @@ public class ReactEditText extends EditText {
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
span.onAttachedToWindow();
@ -590,8 +590,8 @@ public class ReactEditText extends EditText {
@Override
public void onFinishTemporaryDetach() {
super.onFinishTemporaryDetach();
if (mContainsImages && getText() instanceof Spanned) {
Spanned text = (Spanned) getText();
if (mContainsImages) {
Spanned text = getText();
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
for (TextInlineImageSpan span : spans) {
span.onFinishTemporaryDetach();