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:
parent
f5975a97ad
commit
46cc4907e3
|
@ -70,11 +70,14 @@ import android.text.Spanned;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mLayout != null) {
|
if (mLayout != null) {
|
||||||
Spanned text = (Spanned) mLayout.getText();
|
CharSequence text = mLayout.getText();
|
||||||
RCTRawText[] spans = text.getSpans(0, text.length(), RCTRawText.class);
|
if (text instanceof Spanned) {
|
||||||
for (RCTRawText span : spans) {
|
Spanned spannedText = (Spanned) text;
|
||||||
if (span.getReactTag() == tag) {
|
RCTRawText[] spans = spannedText.getSpans(0, text.length(), RCTRawText.class);
|
||||||
return true;
|
for (RCTRawText span : spans) {
|
||||||
|
if (span.getReactTag() == tag) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class ReactTextView extends TextView implements ReactCompoundView {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int reactTagForTouch(float touchX, float touchY) {
|
public int reactTagForTouch(float touchX, float touchY) {
|
||||||
Spanned text = (Spanned) getText();
|
CharSequence text = getText();
|
||||||
int target = getId();
|
int target = getId();
|
||||||
|
|
||||||
int x = (int) touchX;
|
int x = (int) touchX;
|
||||||
|
@ -94,20 +94,21 @@ public class ReactTextView extends TextView implements ReactCompoundView {
|
||||||
int lineEndX = (int) layout.getLineRight(line);
|
int lineEndX = (int) layout.getLineRight(line);
|
||||||
|
|
||||||
// TODO(5966918): Consider extending touchable area for text spans by some DP constant
|
// 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);
|
int index = layout.getOffsetForHorizontal(line, x);
|
||||||
|
|
||||||
// We choose the most inner span (shortest) containing character at the given index
|
// 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
|
// 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
|
// 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
|
// 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) {
|
if (spans != null) {
|
||||||
int targetSpanTextLength = text.length();
|
int targetSpanTextLength = text.length();
|
||||||
for (int i = 0; i < spans.length; i++) {
|
for (int i = 0; i < spans.length; i++) {
|
||||||
int spanStart = text.getSpanStart(spans[i]);
|
int spanStart = spannedText.getSpanStart(spans[i]);
|
||||||
int spanEnd = text.getSpanEnd(spans[i]);
|
int spanEnd = spannedText.getSpanEnd(spans[i]);
|
||||||
if (spanEnd > index && (spanEnd - spanStart) <= targetSpanTextLength) {
|
if (spanEnd > index && (spanEnd - spanStart) <= targetSpanTextLength) {
|
||||||
target = spans[i].getReactTag();
|
target = spans[i].getReactTag();
|
||||||
targetSpanTextLength = (spanEnd - spanStart);
|
targetSpanTextLength = (spanEnd - spanStart);
|
||||||
|
|
|
@ -525,8 +525,8 @@ public class ReactEditText extends EditText {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean verifyDrawable(Drawable drawable) {
|
protected boolean verifyDrawable(Drawable drawable) {
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
if (span.getDrawable() == drawable) {
|
if (span.getDrawable() == drawable) {
|
||||||
|
@ -539,8 +539,8 @@ public class ReactEditText extends EditText {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void invalidateDrawable(Drawable drawable) {
|
public void invalidateDrawable(Drawable drawable) {
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
if (span.getDrawable() == drawable) {
|
if (span.getDrawable() == drawable) {
|
||||||
|
@ -554,8 +554,8 @@ public class ReactEditText extends EditText {
|
||||||
@Override
|
@Override
|
||||||
public void onDetachedFromWindow() {
|
public void onDetachedFromWindow() {
|
||||||
super.onDetachedFromWindow();
|
super.onDetachedFromWindow();
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
span.onDetachedFromWindow();
|
span.onDetachedFromWindow();
|
||||||
|
@ -566,8 +566,8 @@ public class ReactEditText extends EditText {
|
||||||
@Override
|
@Override
|
||||||
public void onStartTemporaryDetach() {
|
public void onStartTemporaryDetach() {
|
||||||
super.onStartTemporaryDetach();
|
super.onStartTemporaryDetach();
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
span.onStartTemporaryDetach();
|
span.onStartTemporaryDetach();
|
||||||
|
@ -578,8 +578,8 @@ public class ReactEditText extends EditText {
|
||||||
@Override
|
@Override
|
||||||
public void onAttachedToWindow() {
|
public void onAttachedToWindow() {
|
||||||
super.onAttachedToWindow();
|
super.onAttachedToWindow();
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
span.onAttachedToWindow();
|
span.onAttachedToWindow();
|
||||||
|
@ -590,8 +590,8 @@ public class ReactEditText extends EditText {
|
||||||
@Override
|
@Override
|
||||||
public void onFinishTemporaryDetach() {
|
public void onFinishTemporaryDetach() {
|
||||||
super.onFinishTemporaryDetach();
|
super.onFinishTemporaryDetach();
|
||||||
if (mContainsImages && getText() instanceof Spanned) {
|
if (mContainsImages) {
|
||||||
Spanned text = (Spanned) getText();
|
Spanned text = getText();
|
||||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||||
for (TextInlineImageSpan span : spans) {
|
for (TextInlineImageSpan span : spans) {
|
||||||
span.onFinishTemporaryDetach();
|
span.onFinishTemporaryDetach();
|
||||||
|
|
Loading…
Reference in New Issue