From 6da6fa92f26eef5e7818ce2c34500fe57e6999b4 Mon Sep 17 00:00:00 2001 From: YuTeh Shen Date: Thu, 20 Dec 2018 10:19:26 +0800 Subject: [PATCH] Fix crash if set text and set selection at the same time. Since text and selection has dependency, handle text selection in updateExtraData as well. --- .../react/views/text/ReactTextUpdate.java | 43 ++++++++++++++++++- .../textinput/ReactTextInputManager.java | 13 +----- .../textinput/ReactTextInputShadowNode.java | 21 ++++++++- 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java index fd1344f0fb714d..26957a58f19399 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextUpdate.java @@ -26,6 +26,8 @@ public class ReactTextUpdate { private final float mPaddingBottom; private final int mTextAlign; private final int mTextBreakStrategy; + private final int mSelectionStart; + private final int mSelectionEnd; private final int mJustificationMode; /** @@ -51,7 +53,9 @@ public ReactTextUpdate( paddingBottom, textAlign, Layout.BREAK_STRATEGY_HIGH_QUALITY, - Layout.JUSTIFICATION_MODE_NONE); + Layout.JUSTIFICATION_MODE_NONE, + -1, + -1); } public ReactTextUpdate( @@ -65,6 +69,33 @@ public ReactTextUpdate( int textAlign, int textBreakStrategy, int justificationMode) { + this(text, + jsEventCounter, + containsImages, + paddingStart, + paddingTop, + paddingEnd, + paddingBottom, + textAlign, + textBreakStrategy, + justificationMode, + -1, + -1); + } + + public ReactTextUpdate( + Spannable text, + int jsEventCounter, + boolean containsImages, + float paddingStart, + float paddingTop, + float paddingEnd, + float paddingBottom, + int textAlign, + int textBreakStrategy, + int justificationMode, + int selectionStart, + int selectionEnd) { mText = text; mJsEventCounter = jsEventCounter; mContainsImages = containsImages; @@ -74,6 +105,8 @@ public ReactTextUpdate( mPaddingBottom = paddingBottom; mTextAlign = textAlign; mTextBreakStrategy = textBreakStrategy; + mSelectionStart = selectionStart; + mSelectionEnd = selectionEnd; mJustificationMode = justificationMode; } @@ -116,4 +149,12 @@ public int getTextBreakStrategy() { public int getJustificationMode() { return mJustificationMode; } + + public int getSelectionStart() { + return mSelectionStart; + } + + public int getSelectionEnd() { + return mSelectionEnd; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 6f9e6e5635c03c..844c691f28ce2c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -198,6 +198,8 @@ public void updateExtraData(ReactEditText view, Object extraData) { TextInlineImageSpan.possiblyUpdateInlineImageSpans(spannable, view); } view.maybeSetText(update); + if (update.getSelectionStart() != UNSET && update.getSelectionEnd() != UNSET) + view.setSelection(update.getSelectionStart(), update.getSelectionEnd()); } } @@ -270,17 +272,6 @@ public void setFontStyle(ReactEditText view, @Nullable String fontStyleString) { } } - @ReactProp(name = "selection") - public void setSelection(ReactEditText view, @Nullable ReadableMap selection) { - if (selection == null) { - return; - } - - if (selection.hasKey("start") && selection.hasKey("end")) { - view.setSelection(selection.getInt("start"), selection.getInt("end")); - } - } - @ReactProp(name = "importantForAutofill") public void setImportantForAutofill(ReactEditText view, @Nullable String value) { int mode = View.IMPORTANT_FOR_AUTOFILL_AUTO; diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index 3189164288ed1c..07114195a44831 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -16,6 +16,7 @@ import android.widget.EditText; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; +import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.annotations.VisibleForTesting; import com.facebook.react.uimanager.LayoutShadowNode; import com.facebook.react.uimanager.PixelUtil; @@ -45,10 +46,13 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode @VisibleForTesting public static final String PROP_TEXT = "text"; @VisibleForTesting public static final String PROP_PLACEHOLDER = "placeholder"; + @VisibleForTesting public static final String PROP_SELECTION = "selection"; // Represents the {@code text} property only, not possible nested content. private @Nullable String mText = null; private @Nullable String mPlaceholder = null; + private int mSelectionStart = UNSET; + private int mSelectionEnd = UNSET; public ReactTextInputShadowNode() { mTextBreakStrategy = (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) ? @@ -172,6 +176,19 @@ public void setPlaceholder(@Nullable String placeholder) { return mPlaceholder; } + @ReactProp(name = PROP_SELECTION) + public void setSelection(@Nullable ReadableMap selection) { + mSelectionStart = mSelectionEnd = UNSET; + if (selection == null) + return; + + if (selection.hasKey("start") && selection.hasKey("end")) { + mSelectionStart = selection.getInt("start"); + mSelectionEnd = selection.getInt("end"); + markUpdated(); + } + } + @Override public void setTextBreakStrategy(@Nullable String textBreakStrategy) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { @@ -205,7 +222,9 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { getPadding(Spacing.BOTTOM), mTextAlign, mTextBreakStrategy, - mJustificationMode); + mJustificationMode, + mSelectionStart, + mSelectionEnd); uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate); } }