Fix TalkBack crash in ReactScrollViewAccessibilityDelegate when a list child has no accessibilityCollectionItem (#58660)

Summary:
With TalkBack on, a `ScrollView` that has `accessibilityCollection` set crashes the app as soon as any direct child of its content view lacks `accessibilityCollectionItem` — e.g. a FlatList `ListHeaderComponent` or `ListFooterComponent`. It reproduces on a common path: a screen reader user navigating away from a list screen. In release builds there is no red box; the process just dies.

```
java.lang.NullPointerException: null cannot be cast to non-null type com.facebook.react.bridge.ReadableMap
  at ReactScrollViewAccessibilityDelegate.onInitializeAccessibilityEventInternal(ReactScrollViewAccessibilityDelegate.kt:74)
  ...
  at android.view.View.clearAccessibilityFocus(View.java:15215)
  at android.view.ViewGroup.removeViewInternal(ViewGroup.java:5611)
  at com.facebook.react.fabric.mounting.SurfaceMountingManager.removeViewAt(SurfaceMountingManager.kt:493)
```

The cause is a non-null cast on a value the code expects to be null:

```kotlin
var accessibilityCollectionItem: ReadableMap? =
    nextChild.getTag(R.id.accessibility_collection_item) as ReadableMap   // throws on null
...
// If this child's accessibilityCollectionItem is null, we'll check one more nested child.
if (nextChild.childCount > 0 && accessibilityCollectionItem == null) {
```

The variable is declared nullable and the null branch right below it was written for exactly this case, but the `as` cast throws before that branch can run. This PR changes it to `as?`, matching the other tag reads in the same file. No behavior change for children that do carry the tag.

It has gone unnoticed because no React Native component sets `accessibilityCollection` itself (it was added in 105a2397b6 for https://github.com/react/react-native/issues/30977), so the early return at the top of the method skips this code for core lists. Any library that sets it to announce a windowed list's real length hits the crash immediately. Observed on 0.87.1 (API 36, new architecture, Hermes); details in https://github.com/iray-tno/hozo/issues/512.

## Changelog:

[ANDROID] [FIXED] - Fix crash in ScrollView accessibility delegate when `accessibilityCollection` is set and a child (e.g. a list header or footer) has no `accessibilityCollectionItem`

Pull Request resolved: https://github.com/react/react-native/pull/58660

Test Plan:
- One-token change (`as` → `as?`); the assigned variable is already `ReadableMap?` and all later uses are null-checked, so types are unchanged.
- Not built or tested locally: the environment had no Android SDK. Relying on CI for the Android build.
- Repro (before this change): Android + TalkBack, a `FlatList` with `ListHeaderComponent`, `accessibilityCollection` on the list and `accessibilityCollectionItem` on cells only; put accessibility focus inside the list and unmount the screen → crash above. Expected after: no crash.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Reviewed By: Abbondanzo

Differential Revision: D121556760

Pulled By: cortinico

fbshipit-source-id: ccbfe470dc53adec3deac3458b83ae2bc08a48cb
This commit is contained in:
iray-tno
2026-09-24 08:36:09 -07:00
committed by meta-codesync[bot]
parent 9fae71c2dd
commit 2915fe02ca
@@ -71,7 +71,7 @@ internal class ReactScrollViewAccessibilityDelegate : AccessibilityDelegateCompa
return
}
var accessibilityCollectionItem: ReadableMap? =
nextChild.getTag(R.id.accessibility_collection_item) as ReadableMap
nextChild.getTag(R.id.accessibility_collection_item) as? ReadableMap
if (nextChild !is ViewGroup) {
return