Skip to content

Commit 46cc490

Browse files
dryganetsfacebook-github-bot
authored andcommitted
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
1 parent f5975a9 commit 46cc490

File tree

3 files changed

+26
-22
lines changed

3 files changed

+26
-22
lines changed

ReactAndroid/src/main/java/com/facebook/react/flat/TextNodeRegion.java

+8-5
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,14 @@ boolean matchesTag(int tag) {
7070
}
7171

7272
if (mLayout != null) {
73-
Spanned text = (Spanned) mLayout.getText();
74-
RCTRawText[] spans = text.getSpans(0, text.length(), RCTRawText.class);
75-
for (RCTRawText span : spans) {
76-
if (span.getReactTag() == tag) {
77-
return true;
73+
CharSequence text = mLayout.getText();
74+
if (text instanceof Spanned) {
75+
Spanned spannedText = (Spanned) text;
76+
RCTRawText[] spans = spannedText.getSpans(0, text.length(), RCTRawText.class);
77+
for (RCTRawText span : spans) {
78+
if (span.getReactTag() == tag) {
79+
return true;
80+
}
7881
}
7982
}
8083
}

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java

+6-5
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public void setText(ReactTextUpdate update) {
7676

7777
@Override
7878
public int reactTagForTouch(float touchX, float touchY) {
79-
Spanned text = (Spanned) getText();
79+
CharSequence text = getText();
8080
int target = getId();
8181

8282
int x = (int) touchX;
@@ -94,20 +94,21 @@ public int reactTagForTouch(float touchX, float touchY) {
9494
int lineEndX = (int) layout.getLineRight(line);
9595

9696
// TODO(5966918): Consider extending touchable area for text spans by some DP constant
97-
if (x >= lineStartX && x <= lineEndX) {
97+
if (text instanceof Spanned && x >= lineStartX && x <= lineEndX) {
98+
Spanned spannedText = (Spanned) text;
9899
int index = layout.getOffsetForHorizontal(line, x);
99100

100101
// We choose the most inner span (shortest) containing character at the given index
101102
// if no such span can be found we will send the textview's react id as a touch handler
102103
// In case when there are more than one spans with same length we choose the last one
103104
// from the spans[] array, since it correspond to the most inner react element
104-
ReactTagSpan[] spans = text.getSpans(index, index, ReactTagSpan.class);
105+
ReactTagSpan[] spans = spannedText.getSpans(index, index, ReactTagSpan.class);
105106

106107
if (spans != null) {
107108
int targetSpanTextLength = text.length();
108109
for (int i = 0; i < spans.length; i++) {
109-
int spanStart = text.getSpanStart(spans[i]);
110-
int spanEnd = text.getSpanEnd(spans[i]);
110+
int spanStart = spannedText.getSpanStart(spans[i]);
111+
int spanEnd = spannedText.getSpanEnd(spans[i]);
111112
if (spanEnd > index && (spanEnd - spanStart) <= targetSpanTextLength) {
112113
target = spans[i].getReactTag();
113114
targetSpanTextLength = (spanEnd - spanStart);

ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java

+12-12
Original file line numberDiff line numberDiff line change
@@ -525,8 +525,8 @@ private void updateImeOptions() {
525525

526526
@Override
527527
protected boolean verifyDrawable(Drawable drawable) {
528-
if (mContainsImages && getText() instanceof Spanned) {
529-
Spanned text = (Spanned) getText();
528+
if (mContainsImages) {
529+
Spanned text = getText();
530530
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
531531
for (TextInlineImageSpan span : spans) {
532532
if (span.getDrawable() == drawable) {
@@ -539,8 +539,8 @@ protected boolean verifyDrawable(Drawable drawable) {
539539

540540
@Override
541541
public void invalidateDrawable(Drawable drawable) {
542-
if (mContainsImages && getText() instanceof Spanned) {
543-
Spanned text = (Spanned) getText();
542+
if (mContainsImages) {
543+
Spanned text = getText();
544544
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
545545
for (TextInlineImageSpan span : spans) {
546546
if (span.getDrawable() == drawable) {
@@ -554,8 +554,8 @@ public void invalidateDrawable(Drawable drawable) {
554554
@Override
555555
public void onDetachedFromWindow() {
556556
super.onDetachedFromWindow();
557-
if (mContainsImages && getText() instanceof Spanned) {
558-
Spanned text = (Spanned) getText();
557+
if (mContainsImages) {
558+
Spanned text = getText();
559559
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
560560
for (TextInlineImageSpan span : spans) {
561561
span.onDetachedFromWindow();
@@ -566,8 +566,8 @@ public void onDetachedFromWindow() {
566566
@Override
567567
public void onStartTemporaryDetach() {
568568
super.onStartTemporaryDetach();
569-
if (mContainsImages && getText() instanceof Spanned) {
570-
Spanned text = (Spanned) getText();
569+
if (mContainsImages) {
570+
Spanned text = getText();
571571
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
572572
for (TextInlineImageSpan span : spans) {
573573
span.onStartTemporaryDetach();
@@ -578,8 +578,8 @@ public void onStartTemporaryDetach() {
578578
@Override
579579
public void onAttachedToWindow() {
580580
super.onAttachedToWindow();
581-
if (mContainsImages && getText() instanceof Spanned) {
582-
Spanned text = (Spanned) getText();
581+
if (mContainsImages) {
582+
Spanned text = getText();
583583
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
584584
for (TextInlineImageSpan span : spans) {
585585
span.onAttachedToWindow();
@@ -590,8 +590,8 @@ public void onAttachedToWindow() {
590590
@Override
591591
public void onFinishTemporaryDetach() {
592592
super.onFinishTemporaryDetach();
593-
if (mContainsImages && getText() instanceof Spanned) {
594-
Spanned text = (Spanned) getText();
593+
if (mContainsImages) {
594+
Spanned text = getText();
595595
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
596596
for (TextInlineImageSpan span : spans) {
597597
span.onFinishTemporaryDetach();

0 commit comments

Comments
 (0)