Fix IllegalStateException in TextView.onEditorAction()

Summary:
This diff fixes a crash caused by an IllegalStateException thrown from the `TextView.onEditorAction()`. This could happen if we don't return false from the `OnEditorActionListener.onEditorAction()` and Android will fallback to the default behaviour, which will try to search and focus the next/previous view in case of `EditorInfo.IME_ACTION_NEXT` or `EditorInfo.IME_ACTION_PREVIOUS` accordingly. Because ReactEditText prevents requesting focus from Android (`ReactEditText.requestFocus()` returns false), the following piece of code from `TextView.onEditorAction()` will crash the app:

```
} else if (actionCode == EditorInfo.IME_ACTION_PREVIOUS) {
    View v = focusSearch(FOCUS_BACKWARD);
    if (v != null) {
        if (!v.requestFocus(FOCUS_BACKWARD)) {
            throw new IllegalStateException("focus search returned a view "
                    + "that wasn't able to take focus!");
        }
    }
    return;

} else if (actionCode == EditorInfo.IME_ACTION_DONE) {
    InputMethodManager imm = InputMethodManager.peekInstance();
    if (imm != null && imm.isActive(this)) {
        imm.hideSoftInputFromWindow(getWindowToken(), 0);
    }
    return;
}
```

To prevent this we have to catch `EditorInfo.IME_ACTION_NEXT` and `EditorInfo.IME_ACTION_PREVIOUS` inside `OnEditorActionListener.onEditorAction()` and prevent the default Android behaviour.

Reviewed By: mdvacca

Differential Revision: D16180306

fbshipit-source-id: 6118257c16a7a4a205ae05da671cd76d3a18d565
This commit is contained in:
Oleksandr Melnykov
2019-07-11 03:51:39 -07:00
committed by Facebook Github Bot
parent b8ccb260ac
commit aa2c682a86
2 changed files with 15 additions and 12 deletions
@@ -499,7 +499,7 @@ public class ReactEditText extends EditText {
return mTextWatcherDelegator;
}
private boolean isMultiline() {
/* package */ boolean isMultiline() {
return (getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0;
}
@@ -6,8 +6,6 @@
*/
package com.facebook.react.views.textinput;
import static android.view.View.FOCUS_FORWARD;
import android.graphics.PorterDuff;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
@@ -904,11 +902,9 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
new TextView.OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) {
// Any 'Enter' action will do
if ((actionId & EditorInfo.IME_MASK_ACTION) > 0 || actionId == EditorInfo.IME_NULL) {
if ((actionId & EditorInfo.IME_MASK_ACTION) != 0 || actionId == EditorInfo.IME_NULL) {
boolean blurOnSubmit = editText.getBlurOnSubmit();
boolean isMultiline =
((editText.getInputType() & InputType.TYPE_TEXT_FLAG_MULTI_LINE) != 0);
boolean isMultiline = editText.isMultiline();
// Motivation:
// * blurOnSubmit && isMultiline => Clear focus; prevent default behaviour (return
@@ -931,13 +927,20 @@ public class ReactTextInputManager extends BaseViewManager<ReactEditText, Layout
}
// Prevent default behavior except when we want it to insert a newline.
return blurOnSubmit || !isMultiline;
} else if (actionId == EditorInfo.IME_ACTION_NEXT) {
View v1 = v.focusSearch(FOCUS_FORWARD);
if (v1 != null && !v.requestFocus(FOCUS_FORWARD)) {
if (blurOnSubmit || !isMultiline) {
return true;
}
return false;
// If we've reached this point, it means that the TextInput has 'blurOnSubmit' set to
// false 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;