From c7d1e48b76a343ef3186aa42479c873c834cf39a Mon Sep 17 00:00:00 2001 From: Rene Weber Date: Fri, 20 Jan 2017 17:50:30 -0800 Subject: [PATCH] TextInput: Avoid firing onSubmitEditing twice on Android Summary: For returnKeyType 'go', 'search' and 'send' Android will call onEditorAction twice, once with IME_NULL and another time with the respective IME_ACTION. This change makes sure to only fire one onSubmitEditing by always returning true in onEditorAction, which causes no subsequent events to be fired by android. Fixes #10443 **Test plan** 1. Create view with TextInput having 'go', 'search' or 'send as `returnKeyType` ```javascript console.log('submit search')}> console.log('submit go')}> console.log('submit send')}> ``` 2. Input some text and click submit button in soft keyboard 3. See event fired only once instead of two times Closes https://github.com/facebook/react-native/pull/11006 Differential Revision: D4439110 Pulled By: hramos fbshipit-source-id: 5573b7f15f862b432600ddd3d61a0852ce51b2b3 --- .../react/tests/TextInputTestCase.java | 52 +++++++++++++++++-- .../src/androidTest/js/TextInputTestModule.js | 12 +++++ .../textinput/ReactTextInputManager.java | 12 ++--- 3 files changed, 64 insertions(+), 12 deletions(-) diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java index ed3494ca691179..9eff4494cadbad 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/tests/TextInputTestCase.java @@ -11,25 +11,26 @@ import android.graphics.Color; import android.text.style.ForegroundColorSpan; import android.util.TypedValue; +import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.inputmethod.EditorInfo; import android.widget.EditText; import com.facebook.react.bridge.JavaScriptModule; import com.facebook.react.testing.ReactAppInstrumentationTestCase; import com.facebook.react.testing.ReactInstanceSpecForTest; +import com.facebook.react.testing.StringRecordingModule; import com.facebook.react.uimanager.PixelUtil; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.textinput.ReactEditText; -import com.facebook.react.views.textinput.ReactTextChangedEvent; -import com.facebook.react.views.textinput.ReactTextInputEvent; /** * Test to verify that TextInput renders correctly */ public class TextInputTestCase extends ReactAppInstrumentationTestCase { + private final StringRecordingModule mRecordingModule = new StringRecordingModule(); + private interface TextInputTestModule extends JavaScriptModule { void setValueRef(String ref, String value); } @@ -99,6 +100,46 @@ public void testTextInputColors() throws Throwable { } } + public void testOnSubmitEditing() throws Throwable { + String testId = "onSubmitTextInput"; + ReactEditText reactEditText = getViewByTestId(testId); + + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_GO); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_DONE); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_NEXT); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_PREVIOUS); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_SEARCH); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_SEND); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_UNSPECIFIED); + fireEditorActionAndCheckRecording(reactEditText, EditorInfo.IME_ACTION_NONE); + } + + private void fireEditorActionAndCheckRecording(final ReactEditText reactEditText, + final int actionId) throws Throwable { + fireEditorActionAndCheckRecording(reactEditText, actionId, true); + fireEditorActionAndCheckRecording(reactEditText, actionId, false); + } + + private void fireEditorActionAndCheckRecording(final ReactEditText reactEditText, + final int actionId, + final boolean blurOnSubmit) throws Throwable { + mRecordingModule.reset(); + + runTestOnUiThread( + new Runnable() { + @Override + public void run() { + reactEditText.requestFocusFromJS(); + reactEditText.setBlurOnSubmit(blurOnSubmit); + reactEditText.onEditorAction(actionId); + } + }); + waitForBridgeAndUIIdle(); + + assertEquals(1, mRecordingModule.getCalls().size()); + assertEquals(!blurOnSubmit, reactEditText.isFocused()); + } + /** * Test that the mentions input has colors displayed correctly. * Removed for being flaky in open source, December 2016 @@ -207,7 +248,8 @@ public void testMetionsInputColors() throws Throwable { @Override protected ReactInstanceSpecForTest createReactInstanceSpecForTest() { return super.createReactInstanceSpecForTest() - .addJSModule(TextInputTestModule.class); + .addJSModule(TextInputTestModule.class) + .addNativeModule(mRecordingModule); } @Override diff --git a/ReactAndroid/src/androidTest/js/TextInputTestModule.js b/ReactAndroid/src/androidTest/js/TextInputTestModule.js index 1dd1c3d0c181a6..924b7e119de9cb 100644 --- a/ReactAndroid/src/androidTest/js/TextInputTestModule.js +++ b/ReactAndroid/src/androidTest/js/TextInputTestModule.js @@ -18,6 +18,8 @@ var Text = require('Text'); var TextInput = require('TextInput'); var View = require('View'); +var Recording = require('NativeModules').Recording; + var app; class TokenizedTextExample extends React.Component { @@ -81,6 +83,10 @@ class TextInputTestApp extends React.Component { app = this; } + handleOnSubmitEditing = (record) => { + Recording.record(record); + }; + render() { return ( @@ -128,6 +134,12 @@ class TextInputTestApp extends React.Component { defaultValue="Text" testID="textInput6" /> + ); 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 714154be4d815a..a09d9802af59a0 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 @@ -688,14 +688,12 @@ public boolean onEditorAction(TextView v, int actionId, KeyEvent keyEvent) { editText.getId(), editText.getText().toString())); } - if (actionId == EditorInfo.IME_ACTION_NEXT || - actionId == EditorInfo.IME_ACTION_PREVIOUS) { - if (editText.getBlurOnSubmit()) { - editText.clearFocus(); - } - return true; + + if (editText.getBlurOnSubmit()) { + editText.clearFocus(); } - return !editText.getBlurOnSubmit(); + + return true; } }); }