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
This commit is contained in:
Emily Janzer
2019-06-14 10:45:29 -07:00
committed by Facebook Github Bot
parent 545b084cc8
commit 616864a2df
@@ -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() {