Skip to content
Permalink
Browse files

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 #15452

Differential Revision: D6775986

Pulled By: hramos

fbshipit-source-id: 6de929937cbbb3e7bd98a708a40700f883cbaef0
  • Loading branch information...
dryganets authored and facebook-github-bot committed Jan 22, 2018
1 parent f5975a9 commit 46cc4907e3e49f5c7b1ac0a1088866f2958f43a1
@@ -70,11 +70,14 @@ boolean matchesTag(int tag) {
}

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;
}
}
}
}
@@ -76,7 +76,7 @@ public void setText(ReactTextUpdate update) {

@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 int reactTagForTouch(float touchX, float touchY) {
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);
@@ -525,8 +525,8 @@ private void updateImeOptions() {

@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 @@ protected boolean verifyDrawable(Drawable drawable) {

@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 void invalidateDrawable(Drawable drawable) {
@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 void onDetachedFromWindow() {
@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 void onStartTemporaryDetach() {
@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 void onAttachedToWindow() {
@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();

0 comments on commit 46cc490

Please sign in to comment.
You can’t perform that action at this time.