Skip to content

Commit 2763fee

Browse files
joevilchesfacebook-github-bot
authored andcommitted
a11y] Let links discovered by dataDetectorType be accessible (#50914)
Summary: Pull Request resolved: #50914 The URL spans generated by Linkify are not actually accessible because we do not update the delegate's virtual views. I also had to change how AccessibilityLinks get generated, since it does not work well if it includes spans that are not `ReactClickableSpans` Differential Revision: D73612119
1 parent 0f277f0 commit 2763fee

File tree

2 files changed

+8
-13
lines changed

2 files changed

+8
-13
lines changed

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewAccessibilityDelegate.kt

+4-9
Original file line numberDiff line numberDiff line change
@@ -270,11 +270,13 @@ internal class ReactTextViewAccessibilityDelegate : ReactAccessibilityDelegate {
270270
return null
271271
}
272272

273-
public class AccessibilityLinks(spans: Array<ClickableSpan?>, text: Spannable) {
273+
public class AccessibilityLinks(text: Spannable) {
274274
private val links: List<AccessibleLink>
275275

276276
init {
277277
val accessibleLinks = mutableListOf<AccessibleLink>()
278+
val spans = text.getSpans(0, text.length, ClickableSpan::class.java)
279+
spans.sortBy { text.getSpanStart(it) }
278280
for (i in spans.indices) {
279281
val span = spans[i]
280282
val start = text.getSpanStart(span)
@@ -288,14 +290,7 @@ internal class ReactTextViewAccessibilityDelegate : ReactAccessibilityDelegate {
288290
link.description = text.subSequence(start, end).toString()
289291
link.start = start
290292
link.end = end
291-
292-
// ID is the reverse of what is expected, since the ClickableSpans are returned in reverse
293-
// order due to being added in reverse order. If we don't do this, focus will move to the
294-
// last link first and move backwards.
295-
//
296-
// If this approach becomes unreliable, we should instead look at their start position and
297-
// order them manually.
298-
link.id = spans.size - 1 - i
293+
link.id = i
299294
accessibleLinks.add(link)
300295
}
301296
links = accessibleLinks

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextViewManager.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import android.content.Context;
1111
import android.os.Build;
1212
import android.text.Spannable;
13+
import android.text.style.ClickableSpan;
1314
import androidx.annotation.NonNull;
1415
import androidx.annotation.Nullable;
1516
import com.facebook.common.logging.FLog;
@@ -26,7 +27,6 @@
2627
import com.facebook.react.uimanager.StateWrapper;
2728
import com.facebook.react.uimanager.ThemedReactContext;
2829
import com.facebook.react.uimanager.annotations.ReactProp;
29-
import com.facebook.react.views.text.internal.span.ReactClickableSpan;
3030
import com.facebook.react.views.text.internal.span.TextInlineImageSpan;
3131
import com.facebook.yoga.YogaMeasureMode;
3232
import java.util.HashMap;
@@ -106,12 +106,12 @@ public void updateExtraData(ReactTextView view, Object extraData) {
106106

107107
// If this text view contains any clickable spans, set a view tag and reset the accessibility
108108
// delegate so that these can be picked up by the accessibility system.
109-
ReactClickableSpan[] clickableSpans =
110-
spannable.getSpans(0, update.getText().length(), ReactClickableSpan.class);
109+
ClickableSpan[] clickableSpans =
110+
spannable.getSpans(0, update.getText().length(), ClickableSpan.class);
111111
view.setTag(
112112
R.id.accessibility_links,
113113
clickableSpans.length > 0
114-
? new ReactTextViewAccessibilityDelegate.AccessibilityLinks(clickableSpans, spannable)
114+
? new ReactTextViewAccessibilityDelegate.AccessibilityLinks(spannable)
115115
: null);
116116
ReactTextViewAccessibilityDelegate.Companion.resetDelegate(
117117
view, view.isFocusable(), view.getImportantForAccessibility());

0 commit comments

Comments
 (0)