From ca0d565a3c9729a68f71bb5572c9971a6ce85d2a Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 14 Mar 2023 05:42:06 -0700 Subject: [PATCH] Back out "1/2 TextInput accessibilityErrorMessage (Talkback, Android)" Summary: This diff is reverting PR https://github.com/facebook/react-native/pull/33468 Due to an increase of java.lang.IllegalStateException caused by the PR Original commit changeset: cd80e9a1be8f Original Phabricator Diff: D38410635 Changelog: [Android][Fixed] - removed logic that calls the [AccessibilityNodeInfo#setError][10] and [#setContentInvalid][13] method to display the error message in the TextInput - Revert of PR https://github.com/facebook/react-native/pull/33468 Reviewed By: NickGerleman, makovkastar Differential Revision: D44032331 fbshipit-source-id: 732ed0cf23e4f30ae00c51dace851a3fdfe65c01 --- .../AndroidTextInputNativeComponent.js | 10 -- Libraries/Components/TextInput/TextInput.d.ts | 8 -- .../Components/TextInput/TextInput.flow.js | 8 -- Libraries/Components/TextInput/TextInput.js | 16 ---- .../TextInput/__tests__/TextInput-test.js | 4 - .../__snapshots__/TextInput-test.js.snap | 2 - .../react/uimanager/BaseViewManager.java | 5 - .../react/views/text/ReactTextUpdate.java | 48 +--------- .../com/facebook/react/views/textinput/BUCK | 1 - .../react/views/textinput/ReactEditText.java | 52 ----------- .../textinput/ReactTextInputManager.java | 20 +--- .../textinput/ReactTextInputShadowNode.java | 12 +-- .../main/res/views/uimanager/values/ids.xml | 5 +- .../AndroidTextInputProps.cpp | 5 - .../androidtextinput/AndroidTextInputProps.h | 1 - .../Accessibility/AccessibilityExample.js | 93 +------------------ 16 files changed, 10 insertions(+), 280 deletions(-) diff --git a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js index d22042ac61b123..e7c28912a0779e 100644 --- a/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js +++ b/Libraries/Components/TextInput/AndroidTextInputNativeComponent.js @@ -166,14 +166,6 @@ export type NativeProps = $ReadOnly<{| 'off', >, - /** - * String to be read by screenreaders to indicate an error state. The acceptable parameters - * of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates - * the error message. Setting accessibilityInvalid to false removes the error message. - */ - accessibilityErrorMessage?: ?Stringish, - accessibilityInvalid?: ?boolean, - /** * Sets the return key to the label. Use it instead of `returnKeyType`. * @platform android @@ -738,8 +730,6 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = { inlineImageLeft: true, editable: true, fontVariant: true, - accessibilityErrorMessage: true, - accessibilityInvalid: true, borderBottomRightRadius: true, borderBottomColor: { process: require('../../StyleSheet/processColor').default, diff --git a/Libraries/Components/TextInput/TextInput.d.ts b/Libraries/Components/TextInput/TextInput.d.ts index 4020cee13398f7..637807aafd3864 100644 --- a/Libraries/Components/TextInput/TextInput.d.ts +++ b/Libraries/Components/TextInput/TextInput.d.ts @@ -531,14 +531,6 @@ export interface TextInputProps TextInputIOSProps, TextInputAndroidProps, AccessibilityProps { - /** - * String to be read by screenreaders to indicate an error state. The acceptable parameters - * of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates - * the error message. Setting accessibilityInvalid to false removes the error message. - */ - accessibilityErrorMessage?: string | undefined; - accessibilityInvalid?: boolean | undefined; - /** * Specifies whether fonts should scale to respect Text Size accessibility settings. * The default is `true`. diff --git a/Libraries/Components/TextInput/TextInput.flow.js b/Libraries/Components/TextInput/TextInput.flow.js index fd1d3acee722c1..57259190f1a449 100644 --- a/Libraries/Components/TextInput/TextInput.flow.js +++ b/Libraries/Components/TextInput/TextInput.flow.js @@ -523,14 +523,6 @@ export type Props = $ReadOnly<{| ...IOSProps, ...AndroidProps, - /** - * String to be read by screenreaders to indicate an error state. The acceptable parameters - * of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates - * the error message. Setting accessibilityInvalid to false removes the error message. - */ - accessibilityErrorMessage?: ?Stringish, - accessibilityInvalid?: ?boolean, - /** * Can tell `TextInput` to automatically capitalize certain characters. * diff --git a/Libraries/Components/TextInput/TextInput.js b/Libraries/Components/TextInput/TextInput.js index 9e7cad98a9248f..ec337de164ef8a 100644 --- a/Libraries/Components/TextInput/TextInput.js +++ b/Libraries/Components/TextInput/TextInput.js @@ -561,14 +561,6 @@ export type Props = $ReadOnly<{| ...IOSProps, ...AndroidProps, - /** - * String to be read by screenreaders to indicate an error state. The acceptable parameters - * of accessibilityErrorMessage is a string. Setting accessibilityInvalid to true activates - * the error message. Setting accessibilityInvalid to false removes the error message. - */ - accessibilityErrorMessage?: ?Stringish, - accessibilityInvalid?: ?boolean, - /** * Can tell `TextInput` to automatically capitalize certain characters. * @@ -1373,12 +1365,6 @@ function InternalTextInput(props: Props): React.Node { } const accessible = props.accessible !== false; - - const accessibilityErrorMessage = - props.accessibilityInvalid === true - ? props.accessibilityErrorMessage - : null; - const focusable = props.focusable !== false; const config = React.useMemo( @@ -1453,7 +1439,6 @@ function InternalTextInput(props: Props): React.Node { ref={ref} {...otherProps} {...eventHandlers} - accessibilityErrorMessage={accessibilityErrorMessage} accessibilityState={_accessibilityState} accessible={accessible} submitBehavior={submitBehavior} @@ -1505,7 +1490,6 @@ function InternalTextInput(props: Props): React.Node { ref={ref} {...otherProps} {...eventHandlers} - accessibilityErrorMessage={accessibilityErrorMessage} accessibilityState={_accessibilityState} accessibilityLabelledBy={_accessibilityLabelledBy} accessible={accessible} diff --git a/Libraries/Components/TextInput/__tests__/TextInput-test.js b/Libraries/Components/TextInput/__tests__/TextInput-test.js index 0e28ffe05484b6..a7900d00835b69 100644 --- a/Libraries/Components/TextInput/__tests__/TextInput-test.js +++ b/Libraries/Components/TextInput/__tests__/TextInput-test.js @@ -186,7 +186,6 @@ describe('TextInput', () => { expect(instance.toJSON()).toMatchInlineSnapshot(` { expect(instance.toJSON()).toMatchInlineSnapshot(` { expect(instance.toJSON()).toMatchInlineSnapshot(` { expect(instance.toJSON()).toMatchInlineSnapshot(` and @@ -31,7 +30,6 @@ public class ReactTextUpdate { private final int mSelectionStart; private final int mSelectionEnd; private final int mJustificationMode; - private @Nullable String mAccessibilityErrorMessage; public boolean mContainsMultipleFragments; @@ -61,8 +59,7 @@ public ReactTextUpdate( Layout.BREAK_STRATEGY_HIGH_QUALITY, Layout.JUSTIFICATION_MODE_NONE, -1, - -1, - null); + -1); } public ReactTextUpdate( @@ -88,8 +85,7 @@ public ReactTextUpdate( textBreakStrategy, justificationMode, -1, - -1, - null); + -1); } public ReactTextUpdate( @@ -111,8 +107,7 @@ public ReactTextUpdate( textBreakStrategy, justificationMode, -1, - -1, - null); + -1); } public ReactTextUpdate( @@ -142,56 +137,21 @@ public ReactTextUpdate( mJustificationMode = justificationMode; } - public ReactTextUpdate( - Spannable text, - int jsEventCounter, - boolean containsImages, - float paddingStart, - float paddingTop, - float paddingEnd, - float paddingBottom, - int textAlign, - int textBreakStrategy, - int justificationMode, - int selectionStart, - int selectionEnd, - @Nullable String accessibilityErrorMessage) { - mText = text; - mJsEventCounter = jsEventCounter; - mContainsImages = containsImages; - mPaddingLeft = paddingStart; - mPaddingTop = paddingTop; - mPaddingRight = paddingEnd; - mPaddingBottom = paddingBottom; - mTextAlign = textAlign; - mTextBreakStrategy = textBreakStrategy; - mSelectionStart = selectionStart; - mSelectionEnd = selectionEnd; - mJustificationMode = justificationMode; - mAccessibilityErrorMessage = accessibilityErrorMessage; - } - public static ReactTextUpdate buildReactTextUpdateFromState( Spannable text, int jsEventCounter, int textAlign, int textBreakStrategy, int justificationMode, - boolean containsMultipleFragments, - @Nullable String accessibilityErrorMessage) { + boolean containsMultipleFragments) { ReactTextUpdate reactTextUpdate = new ReactTextUpdate( text, jsEventCounter, false, textAlign, textBreakStrategy, justificationMode); reactTextUpdate.mContainsMultipleFragments = containsMultipleFragments; - reactTextUpdate.mAccessibilityErrorMessage = accessibilityErrorMessage; return reactTextUpdate; } - public @Nullable String getScreenreaderError() { - return mAccessibilityErrorMessage; - } - public Spannable getText() { return mText; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK index 67538981f1baad..233f1e12611afa 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/BUCK @@ -34,7 +34,6 @@ rn_android_library( react_native_target("java/com/facebook/react/common/mapbuffer:mapbuffer"), react_native_target("java/com/facebook/react/views/view:view"), react_native_target("java/com/facebook/react/config:config"), - react_native_target("res:uimanager"), ] + KOTLIN_STDLIB_DEPS, exported_deps = [ react_native_dep("third-party/android/androidx:appcompat"), 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 8c1b306810e3ad..6e2e24cc29eaa1 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 @@ -30,7 +30,6 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; -import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputConnection; @@ -38,10 +37,8 @@ import androidx.annotation.Nullable; import androidx.appcompat.widget.AppCompatEditText; import androidx.core.view.ViewCompat; -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; import com.facebook.common.logging.FLog; import com.facebook.infer.annotation.Assertions; -import com.facebook.react.R; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactSoftExceptionLogger; import com.facebook.react.common.build.ReactBuildConfig; @@ -160,36 +157,6 @@ public ReactEditText(Context context) { ReactAccessibilityDelegate editTextAccessibilityDelegate = new ReactAccessibilityDelegate( this, this.isFocusable(), this.getImportantForAccessibility()) { - @Override - public void onInitializeAccessibilityNodeInfo( - View host, AccessibilityNodeInfoCompat info) { - super.onInitializeAccessibilityNodeInfo(host, info); - final String accessibilityErrorMessage = - (String) host.getTag(R.id.accessibility_error_message); - boolean contentInvalid = accessibilityErrorMessage == null ? false : true; - if (accessibilityErrorMessage != info.getError()) { - info.setError(accessibilityErrorMessage); - info.setContentInvalid(contentInvalid); - } - } - - @Override - public void onInitializeAccessibilityEvent(View host, AccessibilityEvent event) { - super.onInitializeAccessibilityEvent(host, event); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED - && host.getParent() != null) { - try { - host.getParent().requestSendAccessibilityEvent(host, event); - } catch (AbstractMethodError e) { - FLog.w( - TAG, - host.getParent().getClass().getSimpleName() - + " does not fully implement ViewParent", - e); - } - } - } - @Override public boolean performAccessibilityAction(View host, int action, Bundle args) { if (action == AccessibilityNodeInfo.ACTION_CLICK) { @@ -572,25 +539,6 @@ public int incrementAndGetEventCounter() { return ++mNativeEventCount; } - /** - * Attempt to set an accessibility error or fail silently. EventCounter is the same one used as - * with text. - * - * @param eventCounter - * @param accessibilityErrorMessage - */ - public void maybeSetAccessibilityError( - int eventCounter, @Nullable String accessibilityErrorMessage) { - String previousScreenreaderError = (String) getTag(R.id.accessibility_error_message); - if (!canUpdateWithEventCount(eventCounter) - || previousScreenreaderError == accessibilityErrorMessage) { - return; - } - - setTag(R.id.accessibility_error_message, accessibilityErrorMessage); - sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED); - } - public void maybeSetTextFromJS(ReactTextUpdate reactTextUpdate) { mIsSettingTextFromJS = true; maybeSetText(reactTextUpdate); diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java index e67955e27fd6f8..7059ca3ed48846 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputManager.java @@ -384,7 +384,6 @@ public void updateExtraData(ReactEditText view, Object extraData) { view.maybeSetTextFromState(update); view.maybeSetSelection(update.getJsEventCounter(), selectionStart, selectionEnd); - view.maybeSetAccessibilityError(update.getJsEventCounter(), update.getScreenreaderError()); } } @@ -1339,12 +1338,6 @@ public Object updateState( int currentJustificationMode = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode(); - @Nullable - String accessibilityErrorMessage = - props.hasKey("accessibilityErrorMessage") - ? props.getString("accessibilityErrorMessage") - : null; - return ReactTextUpdate.buildReactTextUpdateFromState( spanned, state.getInt("mostRecentEventCount"), @@ -1352,8 +1345,7 @@ public Object updateState( props, TextLayoutManager.isRTL(attributedString), view.getGravityHorizontal()), textBreakStrategy, TextAttributeProps.getJustificationMode(props, currentJustificationMode), - containsMultipleFragments, - accessibilityErrorMessage); + containsMultipleFragments); } public Object getReactTextUpdate(ReactEditText view, ReactStylesDiffMap props, MapBuffer state) { @@ -1373,6 +1365,7 @@ public Object getReactTextUpdate(ReactEditText view, ReactStylesDiffMap props, M Spannable spanned = TextLayoutManagerMapBuffer.getOrCreateSpannableForText( view.getContext(), attributedString, mReactTextViewManagerCallback); + boolean containsMultipleFragments = attributedString.getMapBuffer(TextLayoutManagerMapBuffer.AS_KEY_FRAGMENTS).getCount() > 1; @@ -1382,12 +1375,6 @@ public Object getReactTextUpdate(ReactEditText view, ReactStylesDiffMap props, M int currentJustificationMode = Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? 0 : view.getJustificationMode(); - @Nullable - String accessibilityErrorMessage = - props.hasKey("accessibilityErrorMessage") - ? props.getString("accessibilityErrorMessage") - : null; - return ReactTextUpdate.buildReactTextUpdateFromState( spanned, state.getInt(TX_STATE_KEY_MOST_RECENT_EVENT_COUNT), @@ -1395,7 +1382,6 @@ public Object getReactTextUpdate(ReactEditText view, ReactStylesDiffMap props, M props, TextLayoutManagerMapBuffer.isRTL(attributedString), view.getGravityHorizontal()), textBreakStrategy, TextAttributeProps.getJustificationMode(props, currentJustificationMode), - containsMultipleFragments, - accessibilityErrorMessage); + containsMultipleFragments); } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java index b9a8d926918f30..d53a7f9083aa60 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactTextInputShadowNode.java @@ -46,15 +46,11 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode @VisibleForTesting public static final String PROP_PLACEHOLDER = "placeholder"; @VisibleForTesting public static final String PROP_SELECTION = "selection"; - @VisibleForTesting - public static final String PROP_ACCESSIBILITY_ERROR_MESSAGE = "accessibilityErrorMessage"; - // Represents the {@code text} property only, not possible nested content. private @Nullable String mText = null; private @Nullable String mPlaceholder = null; private int mSelectionStart = UNSET; private int mSelectionEnd = UNSET; - private @Nullable String mAccessibilityErrorMessage = null; public ReactTextInputShadowNode( @Nullable ReactTextViewManagerCallback reactTextViewManagerCallback) { @@ -198,11 +194,6 @@ public void setPlaceholder(@Nullable String placeholder) { return mPlaceholder; } - @ReactProp(name = PROP_ACCESSIBILITY_ERROR_MESSAGE) - public void setScreenreaderError(String accessibilityErrorMessage) { - mAccessibilityErrorMessage = accessibilityErrorMessage; - } - @ReactProp(name = PROP_SELECTION) public void setSelection(@Nullable ReadableMap selection) { mSelectionStart = mSelectionEnd = UNSET; @@ -256,8 +247,7 @@ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) { mTextBreakStrategy, mJustificationMode, mSelectionStart, - mSelectionEnd, - mAccessibilityErrorMessage); + mSelectionEnd); uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), reactTextUpdate); } } diff --git a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml index 0d7621cb058211..6324b85af44673 100644 --- a/ReactAndroid/src/main/res/views/uimanager/values/ids.xml +++ b/ReactAndroid/src/main/res/views/uimanager/values/ids.xml @@ -39,10 +39,7 @@ - - - - + diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp index fd74bff32a8175..19cb290a3323f2 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.cpp @@ -68,10 +68,6 @@ AndroidTextInputProps::AndroidTextInputProps( "underlineColorAndroid", sourceProps.underlineColorAndroid, {})), - accessibilityErrorMessage(convertRawProp(context, rawProps, - "accessibilityErrorMessage", - sourceProps.accessibilityErrorMessage, - {})), inlineImageLeft(CoreFeatures::enablePropIteratorSetter? sourceProps.inlineImageLeft : convertRawProp(context, rawProps, "inlineImageLeft", sourceProps.inlineImageLeft, @@ -435,7 +431,6 @@ folly::dynamic AndroidTextInputProps::getDynamic() const { props["disableFullscreenUI"] = disableFullscreenUI; props["textBreakStrategy"] = textBreakStrategy; props["underlineColorAndroid"] = toAndroidRepr(underlineColorAndroid); - props["accessibilityErrorMessage"] = accessibilityErrorMessage; props["inlineImageLeft"] = inlineImageLeft; props["inlineImagePadding"] = inlineImagePadding; props["importantForAutofill"] = importantForAutofill; diff --git a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h index 6c627949aee18d..7652984ce15e86 100644 --- a/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h +++ b/ReactCommon/react/renderer/components/textinput/androidtextinput/react/renderer/components/androidtextinput/AndroidTextInputProps.h @@ -120,7 +120,6 @@ class AndroidTextInputProps final : public ViewProps, public BaseTextProps { bool disableFullscreenUI{false}; std::string textBreakStrategy{}; SharedColor underlineColorAndroid{}; - std::string accessibilityErrorMessage{}; std::string inlineImageLeft{}; int inlineImagePadding{0}; std::string importantForAutofill{}; diff --git a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js index da0840dadfaa76..268550b80624eb 100644 --- a/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js +++ b/packages/rn-tester/js/examples/Accessibility/AccessibilityExample.js @@ -1544,88 +1544,9 @@ function DisplayOptionStatusExample({ ); } -function AccessibilityErrorWithButtons(): React.Node { - const [text, setText] = React.useState(''); - const [error, setError] = React.useState(null); - const [accessibilityInvalid, setAccessibilityInvalid] = React.useState(false); - return ( - - - { - setText(newText); - if (newText === 'Error') { - setError('the newText is: ' + newText); - setAccessibilityInvalid(true); - } else { - setError(null); - setAccessibilityInvalid(false); - } - }} - value={text} - style={styles.default} - /> -