critical priority medium complexity testing pending testing specialist Tier 5

Acceptance Criteria

An audit document is produced listing every interactive element in the receipt capture flow with its actual TalkBack label, role, and value as read on a physical Android device
Explore-by-touch (finger drag) correctly focuses each interactive element in the expense form and receipt capture flow without dead zones
Linear swipe navigation (swipe right/left) traverses all interactive elements in a logical order matching the visual layout
TalkBack double-tap to activate works correctly on the attachment indicator, camera trigger, thumbnail, and remove/replace buttons
The assertive live region announcement on threshold crossing is read by TalkBack immediately, interrupting the current utterance
The polite live region announcement on threshold reversal queues correctly and does not interrupt ongoing TalkBack speech
TalkBack custom actions (swipe up/down to access actions) on the receipt thumbnail expose remove and replace options with descriptive labels
No focus is lost or trapped when the camera sheet opens or closes — TalkBack focus returns to the attachment indicator after sheet dismissal
All blocking issues found during the TalkBack audit have corresponding code fixes committed and re-tested on the same device
Audit findings cross-reference the VoiceOver audit (task-010) to identify any platform-specific divergences in Flutter's semantics rendering between iOS and Android

Technical Requirements

frameworks
Flutter
performance requirements
TalkBack announcement latency after threshold crossing must be under 500ms from state emission to spoken output
Camera sheet open/close transition must not cause TalkBack to lose focus for more than 300ms
security requirements
Confirm TalkBack does not read any content hidden via Visibility(visible: false) or Opacity(opacity: 0) that contains PII
ui components
Expense amount text field
ReceiptAttachmentIndicator
Camera capture bottom sheet
ReceiptThumbnailPreview
Remove/Replace action buttons

Execution Context

Execution Tier
Tier 5

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.

Component
Receipt Attachment Indicator
ui low
Epic Risks (2)
medium impact medium prob technical

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.

medium impact low prob integration

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.