TalkBack accessibility audit for receipt capture flow
epic-receipt-capture-and-attachment-ui-accessibility-task-011 — Conduct a structured TalkBack (Android) audit mirroring the VoiceOver audit for the full receipt capture flow. Pay special attention to explore-by-touch focus order, swipe navigation between thumbnail actions, and that live region announcements are read correctly by TalkBack's announcement queue. Document findings and fix all blocking issues before sign-off.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 5 - 253 tasks
Can start after Tier 4 completes
Implementation Notes
TalkBack and VoiceOver can differ in how they handle Flutter's Semantics tree — particularly for custom actions and live regions. If a fix for a VoiceOver issue (task-010) inadvertently breaks TalkBack behavior, prioritize a platform-conditional solution using Platform.isIOS/isAndroid only as a last resort (prefer cross-platform Semantics API). TalkBack's announcement queue behavior differs from VoiceOver: polite announcements may be delayed significantly if TalkBack is mid-sentence — test with longer TalkBack utterances in progress. For focus restoration after bottom sheet dismissal, ensure the sheet uses Flutter's FocusTrap widget and explicitly returns focus to the originating element on close.
Use Flutter's AccessibilityFeatures API if conditional behavior is needed during testing. Consider that Android's explore-by-touch requires sufficient touch target size (44dp enforced in task-008) — re-verify on Android as rendering may differ slightly from iOS.
Testing Requirements
Manual structured audit on a physical Android device (Android 12+, TalkBack 12+). Use the same checklist structure as the VoiceOver audit (task-010) for direct comparison: label completeness, role accuracy, focus order, live region timing, action discoverability, no focus traps. Test both explore-by-touch and linear swipe navigation modes. Test with TalkBack verbose mode enabled to catch implicit labels.
Document each finding with element name, expected vs actual TalkBack output, platform (Android), pass/fail, and fix reference. Re-test all fixes before sign-off. Cross-check findings against task-010 VoiceOver report for platform-divergent Flutter semantics issues.
Flutter's accessibility live region support (SemanticsProperties.liveRegion) has known inconsistencies between iOS VoiceOver and Android TalkBack, and between Flutter versions. Threshold-crossing announcements may fail to fire or double-fire, breaking the accessibility contract for Blindeforbundet users.
Mitigation & Contingency
Mitigation: Test live region announcements on physical devices with VoiceOver and TalkBack enabled from the first iteration. Use the AccessibilityLiveRegionAnnouncer component pattern already established in the project. Verify announcement timing relative to Bloc state emissions to avoid double-fires.
Contingency: If Flutter live regions prove unreliable, implement a platform-channel fallback that calls UIAccessibility.post(notification:) on iOS and AccessibilityManager.sendAccessibilityEvent() on Android directly, bypassing Flutter's abstraction.
The org-configurable threshold must be available at form-render time. If the threshold configuration is fetched asynchronously and not cached, the indicator may briefly show the wrong state (e.g., 'optional' before the threshold loads), confusing users and potentially allowing invalid submissions.
Mitigation & Contingency
Mitigation: Ensure the receipt threshold validator loads and caches the org configuration at app startup or organization selection time, not lazily on form open. Use a loading state in the indicator widget rather than defaulting to 'optional' while configuration is pending.
Contingency: If startup caching is not feasible, treat an unknown threshold as 'receipt required' (fail safe) and surface a clear loading indicator until the configuration resolves, preventing invalid submissions while the config loads.