Skip to content

Commit 53c1a4c

Browse files
joshjhargreavesgrabbou
authored andcommitted
Fix crashes onKeyPress Android
Summary: There appear to be two different types of crashes related to the recent addition of `onKeyPress` on Android introduce in `0.53`. This PR addresses the cause of both of them. Firstly, it seems possible to get an `indexOutOfBoundsException` with some 3rd-party keyboards as observed in #17974 & #17922. I have simplified the backspace determining logic slightly, and also put in an explicit check for zero case so it is not possible to get an indexOutOfBoundsException & it should make sense in the context of the onKeyPress logic. Secondly, it appears that `EditText#onCreateInputConnection` can return null. In this case, if we set `null` to be the target of our subclass of `ReactEditTextInputConnectionWrapper`, we will see the crashes as seen [here](#17974 (comment)), whereby any of methods executed in the `InputConnection` interface can result in a crash. It's hard to reason about the state when `null` is returned from `onCreateInputConnection`, however I would might reason that any soft keyboard input cannot update the `EditText` with a `null` `input connection`, as there is no way of interfacing with the `EditText`. I'm am not sure, if there is a later point where we might return/set this input connection at a later point? As without the `InputConnection` onKeyPress will not work. But for now, this will fix this crash at least. I have not managed to reproduce these crashes myself yet, but users have confirmed that the `indexOutOfBounds` exception is fixed with the 'zero' case and has been confirmed on the respective issues #17974 (comment). For the `null` inputConnection target case, I have verified that explicitly setting the target as null in the constructor of `onCreateInputConnection` results in the same stack trace as the one linked. Here is also a [reference](https://github.com/stripe/stripe-android/pull/392/files#diff-6cc1685c98457d07fd4e2dd83f54d5bb) to the same issue closed with the same fix for another project on github. It is also important to verify that the behavior of `onKeyPress` still functions the same after this change, which can be verified by running the RNTesterProject and the `KeyboardEvents` section in `InputText`. The cases to check that I think are important to check are: - Cursor at beginning of input & backspace - Return key & return key at beginning of input - Select text then press delete - Selection then press a key - Space key - Different keyboard types This should not be a breaking change. [ANDROID] [BUGFIX] [TextInput] - Fixes crashes with TextInput introduced in 0.53. Closes #18114 Differential Revision: D7099570 Pulled By: hramos fbshipit-source-id: 75b2dc468c1ed398a33eb00487c6aa14ae04e5c2
1 parent 67e67ec commit 53c1a4c

File tree

2 files changed

+11
-8
lines changed

2 files changed

+11
-8
lines changed

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,16 @@ protected void onScrollChanged(int horiz, int vert, int oldHoriz, int oldVert) {
174174
@Override
175175
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
176176
ReactContext reactContext = (ReactContext) getContext();
177-
ReactEditTextInputConnectionWrapper inputConnectionWrapper =
178-
new ReactEditTextInputConnectionWrapper(super.onCreateInputConnection(outAttrs), reactContext, this);
177+
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
178+
if (inputConnection != null) {
179+
inputConnection = new ReactEditTextInputConnectionWrapper(inputConnection, reactContext, this);
180+
}
179181

180182
if (isMultiline() && getBlurOnSubmit()) {
181183
// Remove IME_FLAG_NO_ENTER_ACTION to keep the original IME_OPTION
182184
outAttrs.imeOptions &= ~EditorInfo.IME_FLAG_NO_ENTER_ACTION;
183185
}
184-
return inputConnectionWrapper;
186+
return inputConnection;
185187
}
186188

187189
@Override

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

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,14 +94,15 @@ public boolean setComposingText(CharSequence text, int newCursorPosition) {
9494
int previousSelectionEnd = mEditText.getSelectionEnd();
9595
String key;
9696
boolean consumed = super.setComposingText(text, newCursorPosition);
97+
int currentSelectionStart = mEditText.getSelectionStart();
9798
boolean noPreviousSelection = previousSelectionStart == previousSelectionEnd;
98-
boolean cursorDidNotMove = mEditText.getSelectionStart() == previousSelectionStart;
99-
boolean cursorMovedBackwards = mEditText.getSelectionStart() < previousSelectionStart;
100-
if ((noPreviousSelection && cursorMovedBackwards)
101-
|| !noPreviousSelection && cursorDidNotMove) {
99+
boolean cursorDidNotMove = currentSelectionStart == previousSelectionStart;
100+
boolean cursorMovedBackwardsOrAtBeginningOfInput =
101+
(currentSelectionStart < previousSelectionStart) || currentSelectionStart <= 0;
102+
if (cursorMovedBackwardsOrAtBeginningOfInput || (!noPreviousSelection && cursorDidNotMove)) {
102103
key = BACKSPACE_KEY_VALUE;
103104
} else {
104-
key = String.valueOf(mEditText.getText().charAt(mEditText.getSelectionStart() - 1));
105+
key = String.valueOf(mEditText.getText().charAt(currentSelectionStart - 1));
105106
}
106107
dispatchKeyEventOrEnqueue(key);
107108
return consumed;

0 commit comments

Comments
 (0)