Skip to content

Commit

Permalink
Android: Add disableExtractUI prop to TextInput on Android
Browse files Browse the repository at this point in the history
Summary:
On Android, if there is a small amount of space available around a text input (e.g. landscape orientation on a phone), Android may choose to have the user edit the text inside of a full screen text input mode. This behavior isn't always desirable. For example, if your app offers some UI controls for controlling the formatting of the text, you want the controls to be visible while the user is editing the text. This Android feature conflicts with that desired experience because the UI controls would be hidden while the text is being edited.

The `disableExtractUI` prop enables developers to choose whether or not Android's full screen text input editing mode is enabled. When this prop is true, Android's `IME_FLAG_NO_EXTRACT_UI` flag is passed to the `setImeOptions` method.

**Test plan (required)**

Verified `disableExtractUI` works for both `true` and `false` values in a test app.

My team is also using this change in our app.

Adam Comella
Microsoft Corp.
Closes #10900

Differential Revision: D4226483

Pulled By: mkonicek

fbshipit-source-id: 8f1055f6e612b05bafabe6f07a3705dd8788e3da
  • Loading branch information
Adam Comella authored and Facebook Github Bot committed Nov 23, 2016
1 parent 9fb520e commit 1b870d2
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 24 deletions.
10 changes: 10 additions & 0 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,15 @@ const TextInput = React.createClass({
* @platform android
*/
numberOfLines: PropTypes.number,
/**
* When `false`, if there is a small amount of space available around a text input
* (e.g. landscape orientation on a phone), the OS may choose to have the user edit
* the text inside of a full screen text input mode. When `true`, this feature is
* disabled and users will always edit the text directly inside of the text input.
* Defaults to `false`.
* @platform android
*/
disableFullscreenUI: PropTypes.bool,
/**
* If `true`, the keyboard disables the return key when there is no text and
* automatically enables it when there is text. The default value is `false`.
Expand Down Expand Up @@ -708,6 +717,7 @@ const TextInput = React.createClass({
onTextInput={this._onTextInput}
text={this._getText()}
children={children}
disableFullscreenUI={this.props.disableFullscreenUI}
/>;

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

Expand Down Expand Up @@ -74,6 +75,8 @@ public class ReactEditText extends EditText {
private int mStagedInputType;
private boolean mContainsImages;
private boolean mBlurOnSubmit;
private boolean mDisableFullscreen;
private @Nullable String mReturnKeyType;
private @Nullable SelectionWatcher mSelectionWatcher;
private @Nullable ContentSizeWatcher mContentSizeWatcher;
private final InternalKeyListener mKeyListener;
Expand All @@ -97,6 +100,7 @@ public ReactEditText(Context context) {
mIsSettingTextFromJS = false;
mIsJSSettingFocus = false;
mBlurOnSubmit = true;
mDisableFullscreen = false;
mListeners = null;
mTextWatcherDelegator = null;
mStagedInputType = getInputType();
Expand Down Expand Up @@ -254,6 +258,24 @@ public boolean getBlurOnSubmit() {
return mBlurOnSubmit;
}

public void setDisableFullscreenUI(boolean disableFullscreenUI) {
mDisableFullscreen = disableFullscreenUI;
updateImeOptions();
}

public boolean getDisableFullscreenUI() {
return mDisableFullscreen;
}

public void setReturnKeyType(String returnKeyType) {
mReturnKeyType = returnKeyType;
updateImeOptions();
}

public String getReturnKeyType() {
return mReturnKeyType;
}

/*protected*/ int getStagedInputType() {
return mStagedInputType;
}
Expand Down Expand Up @@ -407,6 +429,42 @@ private boolean isMultiline() {
setGravity((getGravity() & ~Gravity.VERTICAL_GRAVITY_MASK) | gravityVertical);
}

private void updateImeOptions() {
// Default to IME_ACTION_DONE
int returnKeyFlag = EditorInfo.IME_ACTION_DONE;
if (mReturnKeyType != null) {
switch (mReturnKeyType) {
case "go":
returnKeyFlag = EditorInfo.IME_ACTION_GO;
break;
case "next":
returnKeyFlag = EditorInfo.IME_ACTION_NEXT;
break;
case "none":
returnKeyFlag = EditorInfo.IME_ACTION_NONE;
break;
case "previous":
returnKeyFlag = EditorInfo.IME_ACTION_PREVIOUS;
break;
case "search":
returnKeyFlag = EditorInfo.IME_ACTION_SEARCH;
break;
case "send":
returnKeyFlag = EditorInfo.IME_ACTION_SEND;
break;
case "done":
returnKeyFlag = EditorInfo.IME_ACTION_DONE;
break;
}
}

if (mDisableFullscreen) {
setImeOptions(returnKeyFlag | EditorInfo.IME_FLAG_NO_FULLSCREEN);
} else {
setImeOptions(returnKeyFlag);
}
}

@Override
protected boolean verifyDrawable(Drawable drawable) {
if (mContainsImages && getText() instanceof Spanned) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ public ReactEditText createViewInstance(ThemedReactContext context) {
ReactEditText editText = new ReactEditText(context);
int inputType = editText.getInputType();
editText.setInputType(inputType & (~InputType.TYPE_TEXT_FLAG_MULTI_LINE));
editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
editText.setReturnKeyType("done");
editText.setTextSize(
TypedValue.COMPLEX_UNIT_PX,
(int) Math.ceil(PixelUtil.toPixelFromSP(ViewDefaults.FONT_SIZE_SP)));
Expand Down Expand Up @@ -475,29 +475,12 @@ public void setKeyboardType(ReactEditText view, @Nullable String keyboardType) {

@ReactProp(name = "returnKeyType")
public void setReturnKeyType(ReactEditText view, String returnKeyType) {
switch (returnKeyType) {
case "done":
view.setImeOptions(EditorInfo.IME_ACTION_DONE);
break;
case "go":
view.setImeOptions(EditorInfo.IME_ACTION_GO);
break;
case "next":
view.setImeOptions(EditorInfo.IME_ACTION_NEXT);
break;
case "none":
view.setImeOptions(EditorInfo.IME_ACTION_NONE);
break;
case "previous":
view.setImeOptions(EditorInfo.IME_ACTION_PREVIOUS);
break;
case "search":
view.setImeOptions(EditorInfo.IME_ACTION_SEARCH);
break;
case "send":
view.setImeOptions(EditorInfo.IME_ACTION_SEND);
break;
}
view.setReturnKeyType(returnKeyType);
}

@ReactProp(name = "disableFullscreenUI", defaultBoolean = false)
public void setDisableFullscreenUI(ReactEditText view, boolean disableFullscreenUI) {
view.setDisableFullscreenUI(disableFullscreenUI);
}

private static final int IME_ACTION_ID = 0x670;
Expand Down

0 comments on commit 1b870d2

Please sign in to comment.