Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1/2 TextInput accessibilityErrorMessage (Talkback, Android) #33468

Closed
wants to merge 160 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
160 commits
Select commit Hold shift + click to select a range
ad9dc3e
draft - testing functionality
fabOnReact Mar 4, 2022
431a9d5
draft
fabOnReact Mar 6, 2022
a4ef7a7
Merge branch 'main' into text-input-errors
fabOnReact Mar 12, 2022
60b6c9b
draft implementation of android_errorMessage
fabOnReact Mar 12, 2022
fb30702
applying same solution from PR 28952
fabOnReact Mar 12, 2022
f22e1f3
adding ErrorExample to TextInputSharedExamples
fabOnReact Mar 12, 2022
caab17c
Merge branch 'main' into text-input-errors
fabOnReact Mar 16, 2022
06c4908
Android NDK: Module react_codegen_rncore depends on undefined modules…
fabOnReact Mar 16, 2022
d1b6182
Revert "Android NDK: Module react_codegen_rncore depends on undefined…
fabOnReact Mar 23, 2022
3092ac8
testing solution from https://github.com/facebook/react-native/pull/2…
fabOnReact Mar 18, 2022
e521859
restore original example
fabOnReact Mar 18, 2022
f92f843
update example
fabOnReact Mar 18, 2022
d94f343
call setError in ReactTextInputManager
fabOnReact Mar 18, 2022
6bd7240
Error onBlur example
fabOnReact Mar 18, 2022
202292a
draft examples
fabOnReact Mar 18, 2022
2820a95
handle errors from diffent type of callbacks
fabOnReact Mar 18, 2022
b8846c9
adding onEndEditing callback
fabOnReact Mar 18, 2022
bf75148
revert changes to ReactEditText onChangeText
fabOnReact Mar 22, 2022
5e9b4c3
add errorMessage to ReactTextUpdate and maybeSetErrorMessage
fabOnReact Mar 23, 2022
97c2dff
update method alphabetical order
fabOnReact Mar 23, 2022
31bfa40
rename android_errorMessage to errorMessageAndroid
fabOnReact Mar 23, 2022
394f794
remove ViewDefault for ERROR
fabOnReact Mar 23, 2022
3a8347a
remove call to setError onAttachedToWindow
fabOnReact Mar 23, 2022
f39e5f1
Merge branch 'main' into text-input-errors
fabOnReact Mar 23, 2022
60bc4e3
adding @platform android to errorMessageAndroid comments
fabOnReact Mar 23, 2022
3c48da3
moving TextInput example at the bottom of the list
fabOnReact Mar 23, 2022
aca0d99
adding errorMessageAndroid to ParagraphAttributes (fabric AndroidText…
fabOnReact Mar 30, 2022
37f0004
adding /ReactAndroid/hermes-engine/.cxx to .gitignore
fabOnReact Mar 31, 2022
0708d07
Merge branch 'main' into text-input-errors
fabOnReact Mar 31, 2022
9df9484
using std::optional<std::string>
fabOnReact Apr 1, 2022
17852df
add comments in ParagraphAttributes
fabOnReact Apr 1, 2022
add6198
draft solution to trigger setError when changing state in Paper
fabOnReact Apr 1, 2022
3d5100c
adding Nullable flag
fabOnReact Apr 1, 2022
53fe1c0
Merge branch 'main' into text-input-errors
fabOnReact Apr 4, 2022
6c0f432
use value_or instead of pointer *paragraphAttributes.errorMessageAndroid
fabOnReact Apr 4, 2022
0ee77ed
adding @VisibleForTesting to PROP_ERROR_MESSAGE
fabOnReact Apr 4, 2022
84edc00
Merge branch 'main' into text-input-errors
fabOnReact Apr 7, 2022
299eba6
Avoid any error visual styling
fabOnReact Apr 8, 2022
27dd208
use androidx Nullable instead of java
fabOnReact Apr 8, 2022
2e660d2
rename errorMessageAndroid in android_accessibilityErrorMessage
fabOnReact Apr 8, 2022
e1c8f54
rename prop to android_accessibilityError
fabOnReact Apr 8, 2022
d4a390b
rename prop in ReactTextUpdate
fabOnReact Apr 8, 2022
f29a21c
rename prop in .xml files
fabOnReact Apr 8, 2022
79c5e4f
adding buck res dependency
fabOnReact Apr 8, 2022
cc602e0
adding comment
fabOnReact Apr 8, 2022
4ba33c3
Paper maybeSetErrorMessage calls errorMessage on every prop updates
fabOnReact Apr 11, 2022
6f69758
renaming ReactTextUpdate getErrorMessage
fabOnReact Apr 11, 2022
4df9d95
rename android_accessibilityError to screenreaderErrorAndroid
fabOnReact Apr 11, 2022
99b4a24
rename android_accessibilityError to screenreaderErrorAndroid java files
fabOnReact Apr 11, 2022
1365f50
rename android_accessibilityError to screenreaderErrorAndroid cpp files
fabOnReact Apr 11, 2022
3a1ef4a
rename android_accessibilityError to screenreaderErrorAndroid .h files
fabOnReact Apr 11, 2022
994089c
Merge branch 'main' into text-input-errors
fabOnReact Apr 11, 2022
eb33c93
fix annoucement delayed to next character
fabOnReact Apr 14, 2022
bb2df1f
trigger call only on TYPE_VIEW_TEXT_CHANGED
fabOnReact Apr 15, 2022
de50984
remove convertion to (View)
fabOnReact Apr 15, 2022
7252c15
adding try catch statement and logging
fabOnReact Apr 15, 2022
586af1f
adding return statement if error does not change
fabOnReact Apr 15, 2022
d1b6f67
remove nested if
fabOnReact Apr 15, 2022
56087d3
only trigger requestSendAccEvent when error present
fabOnReact Apr 15, 2022
3d831a9
remove check on accessibilityErrorMessage != null
fabOnReact Apr 15, 2022
0513007
Merge branch 'main' into text-input-errors
fabOnReact Apr 15, 2022
425056d
Merge branch 'main' into text-input-errors
fabOnReact May 2, 2022
ea9bb4c
Pods update
fabOnReact May 2, 2022
7f7b281
implementing iOS functionalities for https://github.com/facebook/reac…
fabOnReact May 3, 2022
ef89ba2
rename screenreaderErrorAndroid to screenreaderError
fabOnReact May 3, 2022
af8a0bd
Revert "Pods update"
fabOnReact May 3, 2022
29b99ba
update Error example
fabOnReact May 5, 2022
f70870e
Merge branch 'main' into text-input-errors
fabOnReact May 20, 2022
bb4597e
improving iOS solution announce screenreaderError
fabOnReact May 20, 2022
d96a284
fix circleci failures
fabOnReact May 23, 2022
9a58e2e
move screenreaderError to AccessibilityProps
fabOnReact May 23, 2022
9958dcd
removing diffing in viewPropConversions
fabOnReact May 23, 2022
ad56244
rename errorMessage in screenreaderError
fabOnReact May 23, 2022
bb7b0c3
remove screenreaderError from AccessibilityProps
fabOnReact May 23, 2022
195fb0b
using the same default prop for screenreaderError
fabOnReact May 23, 2022
343eea1
update iOS logic to trigger error message
fabOnReact May 24, 2022
521c907
Merge branch 'main' into text-input-errors
fabOnReact May 24, 2022
efba00c
Merge branch 'main' into text-input-errors
fabOnReact May 25, 2022
dac4b96
Rename screenreaderError to accessibilityErrorMessage
fabOnReact Jun 7, 2022
1d00ea8
Merge branch 'main' into text-input-errors
fabOnReact Jun 7, 2022
6bac85e
draft solution Android accessibilityInvalid
fabOnReact Jun 7, 2022
54aca18
draft - basic example with accInvalid
fabOnReact Jun 7, 2022
8e06f08
adding accessibilityInvalid to iOS TextInput props
fabOnReact Jun 7, 2022
ee964b6
moving prop type from AndroidProps to Props
fabOnReact Jun 7, 2022
0e5ad7c
fix flow circleci error
fabOnReact Jun 7, 2022
8670b13
update TextInput-test.js snapshot
fabOnReact Jun 7, 2022
d801b87
rename variable screenreaderError to accessibilityErrorMessage
fabOnReact Jun 7, 2022
53d8464
update Example
fabOnReact Jun 7, 2022
cabb212
rename remaing configs to accessibilityErrorMessage
fabOnReact Jun 7, 2022
318a964
set accessibilityValue to text value if there is no error
fabOnReact Jun 8, 2022
f1a8b00
update Example based on new API updates
fabOnReact Jun 9, 2022
aefa74c
Merge branch 'main' into text-input-errors
fabOnReact Jun 9, 2022
086dce7
adding more AccessibilityError examples
fabOnReact Jun 9, 2022
ddd7f53
handle different scenarios
fabOnReact Jun 9, 2022
9f1e465
minor change
fabOnReact Jun 10, 2022
1574fc4
Merge branch 'main' into text-input-errors
fabOnReact Jun 10, 2022
3b5acf3
iOS - Exception thrown while executing UI block: - RCTUITextView setA…
fabOnReact Jun 13, 2022
f978045
draft solution - announcing accessibilityErrorMessage on iOS Paper
fabOnReact Jun 14, 2022
037089f
include attributedText.string and avoid 2 announcements
fabOnReact Jun 14, 2022
04f5e14
Paper iOS - update accessibilityValue onChangeText
fabOnReact Jun 16, 2022
f594d51
iOS Paper - set error outside of onChangeText
fabOnReact Jun 16, 2022
582b1e8
fix the following scenarios iOS Paper
fabOnReact Jun 16, 2022
e4a95c6
Merge branch 'main' into text-input-errors
fabOnReact Jun 17, 2022
b53ed9d
iOS - apply Paper improvements to Fabric
fabOnReact Jun 17, 2022
8cd7f42
update variable name in RCTUITextField
fabOnReact Jun 17, 2022
dce9b91
test/improve check on accessibilityValue != text
fabOnReact Jun 20, 2022
90aa959
Implement solution for multiline textinput
fabOnReact Jun 20, 2022
3c4296f
avoid initializing lastChar if errorMessageRemoved is false
fabOnReact Jun 20, 2022
3f3312d
Rename var ErrorMessageString -> ScreenReaderError
fabOnReact Jun 20, 2022
9858e54
The attributedText property is nil by default
fabOnReact Jun 20, 2022
16d7d4d
rm update accessibilityValue in RCTBaseTextInputView
fabOnReact Jun 20, 2022
99b39d5
Reintroduce fix - avoid repeat error announcement
fabOnReact Jun 21, 2022
34c5526
update Accessibility Example
fabOnReact Jun 21, 2022
933aa3c
rename _errorMessage to currentScreenreaderError
fabOnReact Jun 21, 2022
30f3f96
implementing strict check in setAttributed string
fabOnReact Jun 21, 2022
de3c2f3
implement previousScreenreaderError check on Fabric
fabOnReact Jun 22, 2022
ce5e52a
using mutableCopy to set previousScreenreaderError value
fabOnReact Jun 22, 2022
b2a6964
rename currentScreenreaderError to currentAccError
fabOnReact Jun 22, 2022
9a3117b
rename currentScreenreaderError to currentAccError in Fabric
fabOnReact Jun 22, 2022
596df4d
fix duplicated VoiceOver announcements
fabOnReact Jun 23, 2022
f5a3bb6
update accessibilityValue onChangeText
fabOnReact Jun 24, 2022
84786a2
update Accessibility Example
fabOnReact Jun 24, 2022
c8790a1
Merge branch 'main' into text-input-errors
fabOnReact Jun 24, 2022
f4acead
Merge branch 'main' into text-input-errors
fabOnReact Jul 28, 2022
63fd956
minor changes
fabOnReact Jul 28, 2022
5e5e2c0
Merge branch 'main' into text-input-errors
fabOnReact Aug 12, 2022
cb0c506
avoid reiterate prop documentation in the docblock
fabOnReact Aug 12, 2022
d85c90a
adding comments as suggested by Brett
fabOnReact Aug 12, 2022
7d0c4db
Merge branch 'main' into text-input-errors
fabOnReact Aug 22, 2022
a92e7f6
adding accessibilityError message to buildReactTextUpdateFromState
fabOnReact Aug 22, 2022
114b4e0
Merge branch 'main' into text-input-errors
fabOnReact Oct 13, 2022
011178c
Merge branch 'main' into text-input-errors
fabOnReact Oct 14, 2022
9c48846
Merge branch 'main' into text-input-errors
fabOnReact Oct 17, 2022
9829e68
minor change
fabOnReact Oct 17, 2022
869dd49
adding flow type for accessibilityErrorMessage
fabOnReact Oct 17, 2022
b43c547
typescript types
fabOnReact Oct 17, 2022
043b24a
eslint Strings must use singlequote. (quotes)
fabOnReact Oct 17, 2022
6c9e233
Merge branch 'main' into text-input-errors
fabOnReact Nov 5, 2022
2818fa4
trigger onChangeText accessibilityErrorMessage with props instead of
fabOnReact Nov 5, 2022
c3ee8f9
this update is triggered with textInputRef.setTextAndSelection(newText,
fabOnReact Nov 5, 2022
5d43830
fabric does not use ReactTextUpdate to announce errorMessage onChange…
fabOnReact Nov 5, 2022
46e3d06
removing accessibilityErrorMessage from ParagraphAttributes state
fabOnReact Nov 5, 2022
af2c906
set accessibilityErrorMessage in case MapBuffer serialization is
fabOnReact Nov 5, 2022
b1b8bf0
adding @Nullable to accessibilityErrorMessage
fabOnReact Nov 5, 2022
f0d0186
change .cpp default value
fabOnReact Nov 5, 2022
b006276
Merge branch 'main' into text-input-errors
fabOnReact Dec 1, 2022
9d1adec
replace readwrite with assign
fabOnReact Dec 1, 2022
e4094c9
remove pressed state
fabOnReact Dec 1, 2022
ca6d811
fix error: auto property synthesis will not synthesize property 'acce…
fabOnReact Dec 5, 2022
bd826f4
Merge branch 'main' into text-input-errors
fabOnReact Dec 5, 2022
1f9c10e
Merge branch 'main' into text-input-errors
fabOnReact Dec 14, 2022
61b049e
adding type null or String
fabOnReact Dec 14, 2022
29a13b6
fix flow errors circleci
fabOnReact Dec 14, 2022
e19d492
Merge branch 'main' into text-input-errors
fabOnReact Jan 19, 2023
085730f
move iOS functionalities to a new PR
fabOnReact Jan 20, 2023
f51645e
updating example
fabOnReact Jan 20, 2023
f138da4
Merge branch 'main' into text-input-errors
fabOnReact Jan 20, 2023
e3f2d68
moving RCTTextInputViewConfig to iOS PR
fabOnReact Jan 23, 2023
954a58f
Merge branch 'main' into text-input-errors
fabOnReact Jan 23, 2023
27b963b
Merge branch 'main' into text-input-errors
fabOnReact Feb 23, 2023
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
10 changes: 10 additions & 0 deletions Libraries/Components/TextInput/AndroidTextInputNativeComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ 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
Expand Down Expand Up @@ -730,6 +738,8 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
inlineImageLeft: true,
editable: true,
fontVariant: true,
accessibilityErrorMessage: true,
accessibilityInvalid: true,
borderBottomRightRadius: true,
borderBottomColor: {
process: require('../../StyleSheet/processColor').default,
Expand Down
8 changes: 8 additions & 0 deletions Libraries/Components/TextInput/TextInput.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,14 @@ 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`.
Expand Down
8 changes: 8 additions & 0 deletions Libraries/Components/TextInput/TextInput.flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,14 @@ 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.
*
Expand Down
16 changes: 16 additions & 0 deletions Libraries/Components/TextInput/TextInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,14 @@ 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.
*
Expand Down Expand Up @@ -1365,6 +1373,12 @@ 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(
Expand Down Expand Up @@ -1439,6 +1453,7 @@ function InternalTextInput(props: Props): React.Node {
ref={ref}
{...otherProps}
{...eventHandlers}
accessibilityErrorMessage={accessibilityErrorMessage}
accessibilityState={_accessibilityState}
accessible={accessible}
submitBehavior={submitBehavior}
Expand Down Expand Up @@ -1490,6 +1505,7 @@ function InternalTextInput(props: Props): React.Node {
ref={ref}
{...otherProps}
{...eventHandlers}
accessibilityErrorMessage={accessibilityErrorMessage}
accessibilityState={_accessibilityState}
accessibilityLabelledBy={_accessibilityLabelledBy}
accessible={accessible}
Expand Down
4 changes: 4 additions & 0 deletions Libraries/Components/TextInput/__tests__/TextInput-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ describe('TextInput', () => {

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessible={true}
allowFontScaling={true}
focusable={true}
Expand Down Expand Up @@ -231,6 +232,7 @@ describe('TextInput compat with web', () => {

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessible={true}
allowFontScaling={true}
focusable={true}
Expand Down Expand Up @@ -315,6 +317,7 @@ describe('TextInput compat with web', () => {

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessibilityState={
Object {
"busy": true,
Expand Down Expand Up @@ -407,6 +410,7 @@ describe('TextInput compat with web', () => {

expect(instance.toJSON()).toMatchInlineSnapshot(`
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessible={true}
allowFontScaling={true}
focusable={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

exports[`TextInput tests should render as expected: should deep render when mocked (please verify output manually) 1`] = `
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessible={true}
allowFontScaling={true}
focusable={true}
Expand Down Expand Up @@ -31,6 +32,7 @@ exports[`TextInput tests should render as expected: should deep render when mock

exports[`TextInput tests should render as expected: should deep render when not mocked (please verify output manually) 1`] = `
<RCTSinglelineTextInputView
accessibilityErrorMessage={null}
accessible={true}
allowFontScaling={true}
focusable={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,11 @@ public void setAccessibilityRole(@NonNull T view, @Nullable String accessibility
view.setTag(R.id.accessibility_role, AccessibilityRole.fromValue(accessibilityRole));
}

@ReactProp(name = "accessibilityErrorMessage")
public void setScreenreaderError(@NonNull T view, @Nullable String accessibilityErrorMessage) {
view.setTag(R.id.accessibility_error_message, accessibilityErrorMessage);
}

@Override
@ReactProp(name = ViewProps.ACCESSIBILITY_COLLECTION)
public void setAccessibilityCollection(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import android.text.Layout;
import android.text.Spannable;
import androidx.annotation.Nullable;

/**
* Class that contains the data needed for a text update. Used by both <Text/> and <TextInput/>
Expand All @@ -30,6 +31,7 @@ public class ReactTextUpdate {
private final int mSelectionStart;
private final int mSelectionEnd;
private final int mJustificationMode;
private @Nullable String mAccessibilityErrorMessage;

public boolean mContainsMultipleFragments;

Expand Down Expand Up @@ -59,7 +61,8 @@ public ReactTextUpdate(
Layout.BREAK_STRATEGY_HIGH_QUALITY,
Layout.JUSTIFICATION_MODE_NONE,
-1,
-1);
-1,
null);
}

public ReactTextUpdate(
Expand All @@ -85,7 +88,8 @@ public ReactTextUpdate(
textBreakStrategy,
justificationMode,
-1,
-1);
-1,
null);
}

public ReactTextUpdate(
Expand All @@ -107,7 +111,8 @@ public ReactTextUpdate(
textBreakStrategy,
justificationMode,
-1,
-1);
-1,
null);
}

public ReactTextUpdate(
Expand Down Expand Up @@ -137,21 +142,56 @@ 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) {
boolean containsMultipleFragments,
@Nullable String accessibilityErrorMessage) {

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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ 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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,18 @@
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;
import android.view.inputmethod.InputMethodManager;
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;
Expand Down Expand Up @@ -157,6 +160,36 @@ 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) {
Expand Down Expand Up @@ -539,6 +572,25 @@ 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);
Expand Down
Loading