Skip to content

Commit 8e5eb63

Browse files
Wei Yanggrabbou
authored andcommitted
add talkback navigation support for links and header (#22447)
Summary: 1. add role description for heading 2. add talkback navigation support for link and header Fixes #22440 Pull Request resolved: #22447 Differential Revision: D14205822 Pulled By: cpojer fbshipit-source-id: 86bfc3bfc851f3544b1962012abaf8d1a357a9d2
1 parent 2b7346f commit 8e5eb63

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

RNTester/js/AccessibilityAndroidExample.android.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,31 @@ class AccessibilityAndroidExample extends React.Component {
111111
</View>
112112
</RNTesterBlock>
113113

114+
<RNTesterBlock title="Touchable with accessibilityRole = header">
115+
<View
116+
accessible={true}
117+
accessibilityLabel="I'm a header, so I read it instead of embedded text."
118+
accessibilityRole="header">
119+
<Text style={{color: 'green'}}>This is</Text>
120+
<Text style={{color: 'blue'}}>
121+
nontouchable accessible view with label.
122+
</Text>
123+
</View>
124+
</RNTesterBlock>
125+
126+
<RNTesterBlock title="Touchable with accessibilityRole = link">
127+
<TouchableWithoutFeedback
128+
onPress={() =>
129+
ToastAndroid.show('Toasts work by default', ToastAndroid.SHORT)
130+
}
131+
accessibilityRole="link">
132+
<View style={styles.embedded}>
133+
<Text>Click me</Text>
134+
<Text>Or not</Text>
135+
</View>
136+
</TouchableWithoutFeedback>
137+
</RNTesterBlock>
138+
114139
<RNTesterBlock title="Touchable with accessibilityRole = button">
115140
<TouchableWithoutFeedback
116141
onPress={() =>

ReactAndroid/src/main/java/com/facebook/react/uimanager/AccessibilityDelegateUtil.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import android.support.v4.view.AccessibilityDelegateCompat;
1010
import android.support.v4.view.ViewCompat;
1111
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
12+
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat;
13+
import android.text.SpannableString;
14+
import android.text.style.URLSpan;
1215
import android.view.View;
1316
import com.facebook.react.R;
1417
import java.util.Locale;
@@ -98,7 +101,6 @@ public static void setDelegate(final View view) {
98101
public void onInitializeAccessibilityNodeInfo(
99102
View host, AccessibilityNodeInfoCompat info) {
100103
super.onInitializeAccessibilityNodeInfo(host, info);
101-
setRole(info, accessibilityRole, view.getContext());
102104
if (!(accessibilityHint == null)) {
103105
String contentDescription=(String)info.getContentDescription();
104106
if (contentDescription != null) {
@@ -108,6 +110,8 @@ public void onInitializeAccessibilityNodeInfo(
108110
info.setContentDescription(accessibilityHint);
109111
}
110112
}
113+
114+
setRole(info, accessibilityRole, view.getContext());
111115
}
112116
});
113117
}
@@ -127,6 +131,18 @@ public static void setRole(AccessibilityNodeInfoCompat nodeInfo, AccessibilityRo
127131
if (Locale.getDefault().getLanguage().equals(new Locale("en").getLanguage())) {
128132
if (role.equals(AccessibilityRole.LINK)) {
129133
nodeInfo.setRoleDescription(context.getString(R.string.link_description));
134+
135+
if (nodeInfo.getContentDescription() != null) {
136+
SpannableString spannable = new SpannableString(nodeInfo.getContentDescription());
137+
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
138+
nodeInfo.setContentDescription(spannable);
139+
}
140+
141+
if (nodeInfo.getText() != null) {
142+
SpannableString spannable = new SpannableString(nodeInfo.getText());
143+
spannable.setSpan(new URLSpan(""), 0, spannable.length(), 0);
144+
nodeInfo.setText(spannable);
145+
}
130146
}
131147
if (role.equals(AccessibilityRole.SEARCH)) {
132148
nodeInfo.setRoleDescription(context.getString(R.string.search_description));
@@ -140,6 +156,12 @@ public static void setRole(AccessibilityNodeInfoCompat nodeInfo, AccessibilityRo
140156
if (role.equals(AccessibilityRole.ADJUSTABLE)) {
141157
nodeInfo.setRoleDescription(context.getString(R.string.adjustable_description));
142158
}
159+
if (role.equals(AccessibilityRole.HEADER)) {
160+
nodeInfo.setRoleDescription(context.getString(R.string.header_description));
161+
final AccessibilityNodeInfoCompat.CollectionItemInfoCompat itemInfo =
162+
AccessibilityNodeInfoCompat.CollectionItemInfoCompat.obtain(0, 1, 0, 1, true);
163+
nodeInfo.setCollectionItemInfo(itemInfo);
164+
}
143165
}
144166
if (role.equals(AccessibilityRole.IMAGEBUTTON)) {
145167
nodeInfo.setClickable(true);

ReactAndroid/src/main/res/views/uimanager/values/strings.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@
2020
name="adjustable_description"
2121
translatable="false"
2222
>Adjustable</string>
23+
<string
24+
name="header_description"
25+
translatable="false"
26+
>Heading</string>
2327
</resources>

0 commit comments

Comments
 (0)