Skip to content

Commit

Permalink
ClassCastException fix: getText() returns CharSequence not Spanned.
Browse files Browse the repository at this point in the history
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 46cc490
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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) {
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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();
Expand Down

0 comments on commit 46cc490

Please sign in to comment.