diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index ecc6165f724..1c7950e4b3c 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -90,8 +90,8 @@ public class ReactEditText extends AppCompatEditText { // *TextChanged events should be triggered. This is less expensive than removing the text // listeners and adding them back again after the text change is completed. protected boolean mIsSettingTextFromJS; - private int mDefaultGravityHorizontal; - private int mDefaultGravityVertical; + private final int mDefaultGravityHorizontal; + private final int mDefaultGravityVertical; /** A count of events sent to JS or C++. */ protected int mNativeEventCount; @@ -120,7 +120,7 @@ public class ReactEditText extends AppCompatEditText { private boolean mDidAttachToWindow = false; private @Nullable String mPlaceholder = null; - private ReactViewBackgroundManager mReactBackgroundManager; + private final ReactViewBackgroundManager mReactBackgroundManager; private StateWrapper mStateWrapper = null; protected boolean mDisableTextDiffing = false; @@ -358,11 +358,11 @@ public class ReactEditText extends AppCompatEditText { } } - public void setContentSizeWatcher(ContentSizeWatcher contentSizeWatcher) { + public void setContentSizeWatcher(@Nullable ContentSizeWatcher contentSizeWatcher) { mContentSizeWatcher = contentSizeWatcher; } - public void setScrollWatcher(ScrollWatcher scrollWatcher) { + public void setScrollWatcher(@Nullable ScrollWatcher scrollWatcher) { mScrollWatcher = scrollWatcher; } @@ -422,7 +422,7 @@ public class ReactEditText extends AppCompatEditText { } } - public void setSelectionWatcher(SelectionWatcher selectionWatcher) { + public void setSelectionWatcher(@Nullable SelectionWatcher selectionWatcher) { mSelectionWatcher = selectionWatcher; } @@ -470,7 +470,7 @@ public class ReactEditText extends AppCompatEditText { return mSubmitBehavior; } - public void setSubmitBehavior(String submitBehavior) { + public void setSubmitBehavior(@Nullable String submitBehavior) { mSubmitBehavior = submitBehavior; } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index 0816eeb102e..376af6a81e6 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -25,7 +25,6 @@ import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.TextWatcher; import android.view.Gravity; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; @@ -798,9 +797,9 @@ public class ReactTextInputManager extends BaseViewManager 0) { LinkedList list = new LinkedList<>(); - for (int i = 0; i < currentFilters.length; i++) { - if (!(currentFilters[i] instanceof InputFilter.LengthFilter)) { - list.add(currentFilters[i]); + for (InputFilter currentFilter : currentFilters) { + if (!(currentFilter instanceof InputFilter.LengthFilter)) { + list.add(currentFilter); } } if (!list.isEmpty()) { @@ -889,14 +888,19 @@ public class ReactTextInputManager extends BaseViewManager { + int surfaceId = reactContext.getSurfaceId(); + EventDispatcher eventDispatcher = getEventDispatcher(reactContext, editText); + if (hasFocus) { + eventDispatcher.dispatchEvent( + new ReactTextInputFocusEvent(surfaceId, editText.getId())); + } else { + eventDispatcher.dispatchEvent(new ReactTextInputBlurEvent(surfaceId, editText.getId())); - eventDispatcher.dispatchEvent( - new ReactTextInputEndEditingEvent( - surfaceId, editText.getId(), editText.getText().toString())); - } + eventDispatcher.dispatchEvent( + new ReactTextInputEndEditingEvent( + surfaceId, editText.getId(), editText.getText().toString())); } }); editText.setOnEditorActionListener( - new TextView.OnEditorActionListener() { - @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) { - if ((actionId & EditorInfo.IME_MASK_ACTION) != 0 || actionId == EditorInfo.IME_NULL) { - boolean isMultiline = editText.isMultiline(); + (v, actionId, keyEvent) -> { + if ((actionId & EditorInfo.IME_MASK_ACTION) != 0 || actionId == EditorInfo.IME_NULL) { + boolean isMultiline = editText.isMultiline(); - boolean shouldSubmit = editText.shouldSubmitOnReturn(); - boolean shouldBlur = editText.shouldBlurOnReturn(); + boolean shouldSubmit = editText.shouldSubmitOnReturn(); + boolean shouldBlur = editText.shouldBlurOnReturn(); - // Motivation: - // * shouldSubmit => Clear focus; prevent default behavior (return true); - // * shouldBlur => Submit; prevent default behavior (return true); - // * !shouldBlur && !shouldSubmit && isMultiline => Perform default behavior (return - // false); - // * !shouldBlur && !shouldSubmit && !isMultiline => Prevent default behavior (return - // true); - if (shouldSubmit) { - EventDispatcher eventDispatcher = getEventDispatcher(reactContext, editText); - eventDispatcher.dispatchEvent( - new ReactTextInputSubmitEditingEvent( - reactContext.getSurfaceId(), - editText.getId(), - editText.getText().toString())); - } - - if (shouldBlur) { - editText.clearFocus(); - } - - // Prevent default behavior except when we want it to insert a newline. - if (shouldBlur || shouldSubmit || !isMultiline) { - return true; - } - - // If we've reached this point, it means that the TextInput has 'submitBehavior' set - // nullish and 'multiline' set to true. But it's still possible to get IME_ACTION_NEXT - // and IME_ACTION_PREVIOUS here in case if 'disableFullscreenUI' is false and Android - // decides to render this EditText in the full screen mode (when a phone has the - // landscape orientation for example). The full screen EditText also renders an action - // button specified by the 'returnKeyType' prop. We have to prevent Android from - // requesting focus from the next/previous focusable view since it must only be - // controlled from JS. - return actionId == EditorInfo.IME_ACTION_NEXT - || actionId == EditorInfo.IME_ACTION_PREVIOUS; + // Motivation: + // * shouldSubmit => Clear focus; prevent default behavior (return true); + // * shouldBlur => Submit; prevent default behavior (return true); + // * !shouldBlur && !shouldSubmit && isMultiline => Perform default behavior (return + // false); + // * !shouldBlur && !shouldSubmit && !isMultiline => Prevent default behavior (return + // true); + if (shouldSubmit) { + EventDispatcher eventDispatcher = getEventDispatcher(reactContext, editText); + eventDispatcher.dispatchEvent( + new ReactTextInputSubmitEditingEvent( + reactContext.getSurfaceId(), + editText.getId(), + editText.getText().toString())); } - return true; + if (shouldBlur) { + editText.clearFocus(); + } + + // Prevent default behavior except when we want it to insert a newline. + if (shouldBlur || shouldSubmit || !isMultiline) { + return true; + } + + // If we've reached this point, it means that the TextInput has 'submitBehavior' set + // nullish and 'multiline' set to true. But it's still possible to get IME_ACTION_NEXT + // and IME_ACTION_PREVIOUS here in case if 'disableFullscreenUI' is false and Android + // decides to render this EditText in the full screen mode (when a phone has the + // landscape orientation for example). The full screen EditText also renders an action + // button specified by the 'returnKeyType' prop. We have to prevent Android from + // requesting focus from the next/previous focusable view since it must only be + // controlled from JS. + return actionId == EditorInfo.IME_ACTION_NEXT + || actionId == EditorInfo.IME_ACTION_PREVIOUS; } + + return true; }); } @@ -1295,7 +1293,7 @@ public class ReactTextInputManager extends BaseViewManager getExportedViewConstants() { return MapBuilder.of( "AutoCapitalizationType", MapBuilder.of( @@ -1403,7 +1401,8 @@ public class ReactTextInputManager extends BaseViewManager