Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ public open class ReactEditText public constructor(context: Context) : AppCompat

public var stagedInputType: Int
internal var stagedAutoCapitalize: Int = 0
internal var stagedCaretHidden: Boolean = false
public var submitBehavior: String? = null
public var dragAndDropFilter: List<String>? = null

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -479,15 +479,10 @@ public open class ReactTextInputManager public constructor() :
} catch (_: IllegalAccessException) {}
}

// Deferred to onAfterUpdateTransaction() so the cursor follows the resolved keyboard type.
@ReactProp(name = "caretHidden", defaultBoolean = false)
public fun setCaretHidden(view: ReactEditText, caretHidden: Boolean) {
if (
view.stagedInputType == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS &&
shouldHideCursorForEmailTextInput()
) {
return
}
view.isCursorVisible = !caretHidden
view.stagedCaretHidden = caretHidden
}

@ReactProp(name = "contextMenuHidden", defaultBoolean = false)
Expand Down Expand Up @@ -744,15 +739,6 @@ public open class ReactTextInputManager public constructor() :
flagsToSet = INPUT_TYPE_KEYBOARD_DECIMAL_PAD
} else if (KEYBOARD_TYPE_EMAIL_ADDRESS.equals(keyboardType, ignoreCase = true)) {
flagsToSet = InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS or InputType.TYPE_CLASS_TEXT

// Set cursor's visibility to False to fix a crash on some Xiaomi devices with Android Q. This
// crash happens when focusing on a email EditText, during which a prompt will be triggered
// but
// the system fail to locate it properly. Here is an example post discussing about this
// issue: https://github.com/facebook/react-native/issues/27204
if (shouldHideCursorForEmailTextInput()) {
view.isCursorVisible = false
}
} else if (KEYBOARD_TYPE_PHONE_PAD.equals(keyboardType, ignoreCase = true)) {
flagsToSet = InputType.TYPE_CLASS_PHONE
} else if (KEYBOARD_TYPE_VISIBLE_PASSWORD.equals(keyboardType, ignoreCase = true)) {
Expand Down Expand Up @@ -907,6 +893,8 @@ public open class ReactTextInputManager public constructor() :
super.onAfterUpdateTransaction(view)
reconcileAutoCapitalize(view)
view.commitStagedInputType()
view.isCursorVisible =
!view.stagedCaretHidden && !shouldHideCursorForEmailTextInput(view.inputType)
// setInputType() clears paint-level font variation settings, so update the typeface last to
// reapply any variation axes after the staged input type is committed.
view.maybeUpdateTypeface()
Expand Down Expand Up @@ -1163,10 +1151,14 @@ public open class ReactTextInputManager public constructor() :
private val DRAWABLE_HANDLE_FIELDS =
arrayOf("mSelectHandleLeft", "mSelectHandleRight", "mSelectHandleCenter")

private fun shouldHideCursorForEmailTextInput(): Boolean {
val manufacturer = Build.MANUFACTURER.lowercase()
return (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q && manufacturer.contains("xiaomi"))
}
// Some Xiaomi devices on Android 10 crash drawing an email field's cursor while showing their
// email suggestion popup: https://github.com/facebook/react-native/issues/27204
private fun shouldHideCursorForEmailTextInput(inputType: Int): Boolean =
(inputType and InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT &&
(inputType and InputType.TYPE_MASK_VARIATION) ==
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS &&
Build.VERSION.SDK_INT == Build.VERSION_CODES.Q &&
Build.MANUFACTURER.lowercase().contains("xiaomi")

private const val IME_ACTION_ID = 0x670

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import org.robolectric.shadows.ShadowBuild

/** Verify {@link EditText} view property being applied properly by {@link ReactTextInputManager} */
@RunWith(RobolectricTestRunner::class)
Expand Down Expand Up @@ -377,6 +379,42 @@ class ReactTextInputPropertyTest {
assertThat(view.inputType and generalKeyboardTypeFlags).isEqualTo(emailTypeFlags)
}

@Test
fun testCaretHidden() {
manager.updateProperties(view, buildStyles("keyboardType", "email-address"))
assertThat(view.isCursorVisible).isTrue

manager.updateProperties(view, buildStyles("caretHidden", true))
assertThat(view.isCursorVisible).isFalse

manager.updateProperties(view, buildStyles("caretHidden", false))
assertThat(view.isCursorVisible).isTrue
}

@Test
@Config(sdk = [Build.VERSION_CODES.Q])
fun testEmailCursorStaysHiddenOnXiaomiAndroid10WhenCaretHiddenIsUpdated() {
ShadowBuild.setManufacturer("Xiaomi")

manager.updateProperties(view, buildStyles("keyboardType", "email-address"))
assertThat(view.isCursorVisible).isFalse

manager.updateProperties(view, buildStyles("caretHidden", false))
assertThat(view.isCursorVisible).isFalse
}

@Test
@Config(sdk = [Build.VERSION_CODES.Q])
fun testCaretHiddenStillAppliesToOtherFieldsOnXiaomiAndroid10() {
ShadowBuild.setManufacturer("Xiaomi")

manager.updateProperties(view, buildStyles("caretHidden", true))
assertThat(view.isCursorVisible).isFalse

manager.updateProperties(view, buildStyles("caretHidden", false))
assertThat(view.isCursorVisible).isTrue
}

@Test
fun testKeyboardTypeUrl() {
manager.updateProperties(view, buildStyles("keyboardType", "url"))
Expand Down
Loading