diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java index de7178d76..52a18a40c 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -21,11 +21,14 @@ import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.TextWatcher; +import android.text.method.KeyListener; +import android.text.method.QwertyKeyListener; import android.text.style.AbsoluteSizeSpan; import android.text.style.BackgroundColorSpan; import android.text.style.ForegroundColorSpan; import android.view.Gravity; import android.view.KeyEvent; +import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; @@ -65,6 +68,9 @@ public class ReactEditText extends EditText { private int mStagedInputType; private boolean mContainsImages; private @Nullable SelectionWatcher mSelectionWatcher; + private final InternalKeyListener mKeyListener; + + private static KeyListener sKeyListener = QwertyKeyListener.getInstanceForFullKeyboard(); public ReactEditText(Context context) { super(context); @@ -81,6 +87,7 @@ public class ReactEditText extends EditText { mListeners = null; mTextWatcherDelegator = null; mStagedInputType = getInputType(); + mKeyListener = new InternalKeyListener(); } // After the text changes inside an EditText, TextView checks if a layout() has been requested. @@ -190,6 +197,12 @@ public class ReactEditText extends EditText { public void setInputType(int type) { super.setInputType(type); mStagedInputType = type; + + // We override the KeyListener so that all keys on the soft input keyboard as well as hardware + // keyboards work. Some KeyListeners like DigitsKeyListener will display the keyboard but not + // accept all input from it + mKeyListener.setInputType(type); + setKeyListener(mKeyListener); } // VisibleForTesting from {@link TextInputEventsTestCase}. @@ -419,4 +432,57 @@ public class ReactEditText extends EditText { } } } + + /* + * This class is set as the KeyListener for the underlying TextView + * It does two things + * 1) Provides the same answer to getInputType() as the real KeyListener would have which allows + * the proper keyboard to pop up on screen + * 2) Permits all keyboard input through + */ + private static class InternalKeyListener implements KeyListener { + + private int mInputType = 0; + + public InternalKeyListener() { + } + + public void setInputType(int inputType) { + mInputType = inputType; + } + + /* + * getInputType will return whatever value is passed in. This will allow the proper keyboard + * to be shown on screen but without the actual filtering done by other KeyListeners + */ + @Override + public int getInputType() { + return mInputType; + } + + /* + * All overrides of key handling defer to the underlying KeyListener which is shared by all + * ReactEditText instances. It will basically allow any/all keyboard input whether from + * physical keyboard or from soft input. + */ + @Override + public boolean onKeyDown(View view, Editable text, int keyCode, KeyEvent event) { + return sKeyListener.onKeyDown(view, text, keyCode, event); + } + + @Override + public boolean onKeyUp(View view, Editable text, int keyCode, KeyEvent event) { + return sKeyListener.onKeyUp(view, text, keyCode, event); + } + + @Override + public boolean onKeyOther(View view, Editable text, KeyEvent event) { + return sKeyListener.onKeyOther(view, text, event); + } + + @Override + public void clearMetaKeyState(View view, Editable content, int states) { + sKeyListener.clearMetaKeyState(view, content, states); + } + } } 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 ed0d84935..a9b071c72 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 @@ -11,6 +11,7 @@ package com.facebook.react.views.textinput; import javax.annotation.Nullable; +import java.util.LinkedList; import java.util.Map; import android.graphics.PorterDuff; @@ -246,13 +247,43 @@ public class ReactTextInputManager extends @ReactProp(name = "maxLength") public void setMaxLength(ReactEditText view, @Nullable Integer maxLength) { + InputFilter [] currentFilters = view.getFilters(); + InputFilter[] newFilters = EMPTY_FILTERS; + if (maxLength == null) { - view.setFilters(EMPTY_FILTERS); + if (currentFilters.length > 0) { + LinkedList list = new LinkedList<>(); + for (int i = 0; i < currentFilters.length; i++) { + if (!(currentFilters[i] instanceof InputFilter.LengthFilter)) { + list.add(currentFilters[i]); + } + } + if (list.size() > 0) { + newFilters = (InputFilter[])list.toArray(); + } + } } else { - InputFilter[] filterArray = new InputFilter[1]; - filterArray[0] = new InputFilter.LengthFilter(maxLength); - view.setFilters(filterArray); + if (currentFilters.length > 0) { + newFilters = currentFilters; + boolean replaced = false; + for (int i = 0; i < currentFilters.length; i++) { + if (currentFilters[i] instanceof InputFilter.LengthFilter) { + currentFilters[i] = new InputFilter.LengthFilter(maxLength); + replaced = true; + } + } + if (!replaced) { + newFilters = new InputFilter[currentFilters.length + 1]; + System.arraycopy(currentFilters, 0, newFilters, 0, currentFilters.length); + currentFilters[currentFilters.length] = new InputFilter.LengthFilter(maxLength); + } + } else { + newFilters = new InputFilter[1]; + newFilters[0] = new InputFilter.LengthFilter(maxLength); + } } + + view.setFilters(newFilters); } @ReactProp(name = "autoCorrect")