From 616864a2dfd9b8cadb3a55e51347c2ccfd341ab5 Mon Sep 17 00:00:00 2001 From: Emily Janzer Date: Fri, 14 Jun 2019 10:40:20 -0700 Subject: [PATCH] Focus text input on accessibility tap Summary: There's an issue with TextInput on Android where if you have TalkBack enabled, double tapping doesn't focus the text input. It turns out this is because we ignore all focus events that aren't from JS in ReactEditText. This diff makes an exception for the accessibility click event. I think this should also fix https://github.com/facebook/react-native/issues/17624 Reviewed By: lunaleaps Differential Revision: D15818103 fbshipit-source-id: 354728b58f1023c4d44edd48337c8daa8ea15c0c --- .../react/views/textinput/ReactEditText.java | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) 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 7f8137c9c4a..94f346ec40d 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 @@ -12,6 +12,7 @@ import android.graphics.Rect; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Bundle; import android.text.Editable; import android.text.InputType; import android.text.SpannableStringBuilder; @@ -25,10 +26,13 @@ import android.view.Gravity; import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import androidx.core.view.AccessibilityDelegateCompat; +import androidx.core.view.ViewCompat; import com.facebook.infer.annotation.Assertions; import com.facebook.react.bridge.ReactContext; import com.facebook.react.uimanager.UIManagerModule; @@ -60,8 +64,8 @@ public class ReactEditText extends EditText { // listeners and adding them back again after the text change is completed. protected boolean mIsSettingTextFromJS; // This component is controlled, so we want it to get focused only when JS ask it to do so. - // Whenever android requests focus (which it does for random reasons), it will be ignored. - private boolean mIsJSSettingFocus; + // Whenever android requests focus, except for accessibility click, it will be ignored. + private boolean mShouldAllowFocus; private int mDefaultGravityHorizontal; private int mDefaultGravityVertical; protected int mNativeEventCount; @@ -98,7 +102,7 @@ public class ReactEditText extends EditText { mNativeEventCount = 0; mMostRecentEventCount = 0; mIsSettingTextFromJS = false; - mIsJSSettingFocus = false; + mShouldAllowFocus = false; mBlurOnSubmit = null; mDisableFullscreen = false; mListeners = null; @@ -116,6 +120,19 @@ public class ReactEditText extends EditText { && Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { setLayerType(View.LAYER_TYPE_SOFTWARE, null); } + + ViewCompat.setAccessibilityDelegate(this, new AccessibilityDelegateCompat() { + @Override + public boolean performAccessibilityAction(View host, int action, Bundle args) { + if (action == AccessibilityNodeInfo.ACTION_CLICK) { + mShouldAllowFocus = true; + requestFocus(); + mShouldAllowFocus = false; + return true; + } + return super.performAccessibilityAction(host, action, args); + } + }); } // After the text changes inside an EditText, TextView checks if a layout() has been requested. @@ -208,9 +225,11 @@ public class ReactEditText extends EditText { if (isFocused()) { return true; } - if (!mIsJSSettingFocus) { + + if (!mShouldAllowFocus) { return false; } + setFocusableInTouchMode(true); boolean focused = super.requestFocus(direction, previouslyFocusedRect); if (getShowSoftInputOnFocus()) { @@ -361,9 +380,9 @@ public class ReactEditText extends EditText { // VisibleForTesting from {@link TextInputEventsTestCase}. public void requestFocusFromJS() { - mIsJSSettingFocus = true; + mShouldAllowFocus = true; requestFocus(); - mIsJSSettingFocus = false; + mShouldAllowFocus = false; } /* package */ void clearFocusFromJS() {