Permalink
Browse files

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
<View>
           <TextInput
                returnKeyType='search'
                onSubmitEditing={event => console.log('submit search')}></TextInput>

           <TextInput
                returnKeyType='go'
                onSubmitEditing={event => console.log('submit go')}></TextInput>

         <TextInput
              returnKeyType='send'
              onSubmitEditing={event => console.log('submit send')}></TextInput>
</View>
```

2. Input some text and click submit button in soft keyboard
3. See event fired only once instead of two times
Closes #11006

Differential Revision: D4439110

Pulled By: hramos

fbshipit-source-id: 5573b7f15f862b432600ddd3d61a0852ce51b2b3
  • Loading branch information...
reneweb authored and facebook-github-bot committed Jan 21, 2017
1 parent f521e99 commit 116916b98da65b778149058e11bef517458a4e54
@@ -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
@@ -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 (
<View style={styles.container}>
@@ -128,6 +134,12 @@ class TextInputTestApp extends React.Component {
defaultValue="Text"
testID="textInput6"
/>
<TextInput
ref="onSubmitTextInput"
onSubmitEditing={this.handleOnSubmitEditing.bind(this, 'onSubmit')}
defaultValue=""
testID="onSubmitTextInput"
/>
<TokenizedTextExample />
</View>
);
@@ -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;
}
});
}

0 comments on commit 116916b

Please sign in to comment.