Skip to content

Commit fb6185e

Browse files
dhleongyayvery
authored andcommitted
Fix: a11y crash when an accessible link is ellipsized away (#41)
1 parent 973dc1e commit fb6185e

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,9 +636,18 @@ protected void onPopulateNodeForVirtualView(
636636
return;
637637
}
638638

639+
// NOTE: The span may not actually have visible bounds within its parent,
640+
// due to line limits, etc.
641+
final Rect bounds = getBoundsInParent(accessibleTextSpan);
642+
if (bounds == null) {
643+
node.setContentDescription("");
644+
node.setBoundsInParent(new Rect(0, 0, 1, 1));
645+
return;
646+
}
647+
639648
node.setContentDescription(accessibleTextSpan.description);
640649
node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);
641-
node.setBoundsInParent(getBoundsInParent(accessibleTextSpan));
650+
node.setBoundsInParent(bounds);
642651
node.setRoleDescription(mView.getResources().getString(R.string.link_description));
643652
node.setClassName(AccessibilityRole.getValue(AccessibilityRole.BUTTON));
644653
}
@@ -655,10 +664,19 @@ private Rect getBoundsInParent(AccessibilityLinks.AccessibleLink accessibleLink)
655664
return new Rect(0, 0, textView.getWidth(), textView.getHeight());
656665
}
657666

658-
Rect rootRect = new Rect();
659-
660667
double startOffset = accessibleLink.start;
661668
double endOffset = accessibleLink.end;
669+
670+
// Ensure the link hasn't been ellipsized away; in such cases,
671+
// getPrimaryHorizontal will crash (and the link isn't rendered anyway).
672+
int startOffsetLineNumber = textViewLayout.getLineForOffset((int) startOffset);
673+
int lineEndOffset = textViewLayout.getLineEnd(startOffsetLineNumber);
674+
if (startOffset > lineEndOffset) {
675+
return null;
676+
}
677+
678+
Rect rootRect = new Rect();
679+
662680
double startXCoordinates = textViewLayout.getPrimaryHorizontal((int) startOffset);
663681

664682
final Paint paint = new Paint();
@@ -668,7 +686,6 @@ private Rect getBoundsInParent(AccessibilityLinks.AccessibleLink accessibleLink)
668686
paint.setTextSize(textSize);
669687
int textWidth = (int) Math.ceil(paint.measureText(accessibleLink.description));
670688

671-
int startOffsetLineNumber = textViewLayout.getLineForOffset((int) startOffset);
672689
int endOffsetLineNumber = textViewLayout.getLineForOffset((int) endOffset);
673690
boolean isMultiline = startOffsetLineNumber != endOffsetLineNumber;
674691
textViewLayout.getLineBounds(startOffsetLineNumber, rootRect);

packages/rn-tester/js/examples/Accessibility/AccessibilityAndroidExample.android.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ class AccessibilityAndroidExample extends React.Component<
6565
render(): React.Node {
6666
return (
6767
<RNTesterPage title={'Accessibility Android APIs'}>
68+
<RNTesterBlock title="Ellipsized Accessible Links">
69+
<Text numberOfLines={3}>
70+
<Text>
71+
Bacon {this.state.count} Ipsum{'\n'}
72+
</Text>
73+
<Text>Dolor sit amet{'\n'}</Text>
74+
<Text>Eggsecetur{'\n'}</Text>
75+
<Text>{'\n'}</Text>
76+
<Text accessibilityRole="link" onPress={this._addOne}>
77+
http://github.com
78+
</Text>
79+
</Text>
80+
</RNTesterBlock>
81+
6882
<RNTesterBlock title="LiveRegion">
6983
<TouchableWithoutFeedback onPress={this._addOne}>
7084
<View style={styles.embedded}>

0 commit comments

Comments
 (0)