Skip to content

Commit 9195e52

Browse files
idoyanameta-codesync[bot]
authored andcommitted
fix: show the soft keyboard when a long-press starts text selection in TextInput on Android (#57471)
Summary: On Android, long-pressing text in a `TextInput` while the soft keyboard is hidden starts text selection (highlight + Cut/Copy toolbar) and focuses the field — but the soft keyboard never appears, leaving the user unable to type over the selection. This happens both when the input was unfocused and when it was focused with the keyboard dismissed. Root cause: `ReactEditText.onAttachedToWindow()` calls `super.setTextIsSelectable(true)` (a `removeClippedSubviews` workaround, #6805). That makes `isTextSelectable()` return `true`, so the platform `Editor#startActionModeInternal()` skips its own "Show the IME to be able to replace text" branch — it is gated on `!isTextSelectable()` and deliberately skips read-only selectable text, which every RN `TextInput` now masquerades as. RN's own keyboard paths cover only clicks and programmatic focus (see the comment on `requestFocusProgrammatically()`); focus gained through long-press selection is a third path neither covers. Fix: compensate in `ReactEditText`, mirroring the platform branch it opted out of — - request the keyboard when a selection/insertion action mode is created (`onCreateActionMode`), and - when focus is gained with a non-collapsed selection (`onFocusChanged`) — the action mode can be created before the view becomes the IME-served view, so this re-requests once focus has landed. Both sites go through a shared guard (`isEnabled` — the `editable` prop maps to it, `isInTouchMode`, `showSoftInputOnFocus`) that mirrors `requestFocusProgrammatically()`, so read-only inputs and `showSoftInputOnFocus={false}` are unaffected. `showSoftInput` is idempotent, so an already-visible keyboard is a no-op. Fixes #57470 (reproduced there with a bare `TextInput` in a plain `View`, no third-party components). ## Changelog: [ANDROID] [FIXED] - Show the soft keyboard when a long-press starts text selection in TextInput Pull Request resolved: #57471 Test Plan: RNTester TextInput example on a Pixel 10 Pro (Android 16, Gboard), `-PreactNativeArchitectures=arm64-v8a`: **Before (main, `0015d1e4f9`)** — long-press a word in the prefilled "Default color text" field with the keyboard hidden: - word selected + Cut/Copy toolbar, **no keyboard** - logcat: **zero** `ImeTracker` events; `dumpsys input_method` → `mInputShown=false` **After (this change)** — same gestures: - Unfocused field, long-press a word → selection + toolbar + **keyboard appears**: `ImeTracker: onRequestShow at ORIGIN_CLIENT reason SHOW_SOFT_INPUT` → `onShown`; `mInputShown=true` - Focused field, dismiss keyboard (back), long-press → **keyboard appears** (same trace) - Plain tap → unchanged (framework `fromUser=true` request + RN's existing click path, same as before the change) - Selection is preserved and the selection toolbar stays up while the keyboard shows — matching stock `EditText` behavior `./gradlew :packages:react-native:ReactAndroid:ktfmtCheck` passes. Reviewed By: javache Differential Revision: D110990211 Pulled By: Abbondanzo fbshipit-source-id: fcb8f362d9fcdb0688bd6c92eda25687b3e42ec4
1 parent d13d2b0 commit 9195e52

1 file changed

Lines changed: 23 additions & 0 deletions

File tree

  • packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
258258
if (contextMenuHidden) {
259259
return false
260260
}
261+
// setTextIsSelectable(true) (see onAttachedToWindow) makes the platform Editor
262+
// treat this view as read-only selectable text and skip its "Show the IME to be
263+
// able to replace text" branch when a selection or insertion action mode starts
264+
// (Editor#startActionModeInternal gates it on !isTextSelectable()). Compensate
265+
// here so long-pressing an editable input summons the keyboard, matching stock
266+
// EditText behavior.
267+
showSoftKeyboardIfEditable()
261268
menu.removeItem(android.R.id.pasteAsPlainText)
262269
return true
263270
}
@@ -499,6 +506,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
499506
if (focused && selectionWatcher != null) {
500507
selectionWatcher?.onSelectionChanged(selectionStart, selectionEnd)
501508
}
509+
// Gaining focus with a non-collapsed selection means focus arrived through a
510+
// long-press text selection rather than a tap or programmatic focus — the one focus
511+
// path that never requests the soft keyboard (see onCreateActionMode). The action
512+
// mode can be created before this view becomes the IME-served view, so request the
513+
// keyboard again now that focus has landed.
514+
if (focused && hasSelection()) {
515+
showSoftKeyboardIfEditable()
516+
}
502517
}
503518

504519
internal fun setSelectionWatcher(selectionWatcher: SelectionWatcher?) {
@@ -909,6 +924,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
909924

910925
protected fun showSoftKeyboard(): Boolean = inputMethodManager.showSoftInput(this, 0)
911926

927+
// Mirrors the guard on requestFocusProgrammatically(), plus editability ("editable"
928+
// prop maps to isEnabled): never summon the keyboard for a read-only input.
929+
private fun showSoftKeyboardIfEditable() {
930+
if (isEnabled && isInTouchMode && showSoftInputOnFocus) {
931+
showSoftKeyboard()
932+
}
933+
}
934+
912935
protected fun hideSoftKeyboard() {
913936
inputMethodManager.hideSoftInputFromWindow(windowToken, 0)
914937
}

0 commit comments

Comments
 (0)