fix(ios): isolate rest timer liveRegion from 1Hz text semantics - #568
Closed
cursor[bot] wants to merge 2 commits into
Closed
fix(ios): isolate rest timer liveRegion from 1Hz text semantics#568cursor[bot] wants to merge 2 commits into
cursor[bot] wants to merge 2 commits into
Conversation
Remove the standalone 0.dp Box with liveRegion=Polite semantics in RestTimerCard and attach liveRegion=Polite + contentDescription= lastAnnouncedText onto the visible timer Text instead. The zero-size liveRegion node increased accessibility-element disposal churn during the 1Hz rest-timer recomposition and raced iOS UIAccessibility's AX-tree poll, triggering EXC_BAD_ACCESS (SIGSEGV) in Compose Multiplatform's AccessibilityElement.contentOffset/bounds path (Accessibility.uikit.kt:725-726) when AXRuntime queried accessibilityFrame on a disposed element. Relocating the semantics onto a stable, visible, non-zero-size element that persists across ticks eliminates the zero-size AX node while preserving the throttled VoiceOver/TalkBack countdown announcements at 5s/10s/0s/paused intervals (the LaunchedEffect/lastAnnouncedText logic is unchanged). Bounded to RestTimerCard.kt only. Complements the CMP 1.10.3 -> 1.11.1 upgrade already on main (upstream JetBrains/compose-multiplatform#5543). RCA: GPT-5.5 xhigh (issuecomment-4734439771). Fixes #565
PR #567 moved liveRegion onto the countdown Text, but Text still exposes a text semantic that updates every second. Live regions notify on text OR contentDescription changes, so throttled announcements were broken and VoiceOver/TalkBack could fire every tick during rest. Restore a dedicated announcement node with clearAndSetSemantics (only lastAnnouncedText) and use 1.dp instead of 0.dp to avoid the iOS UIAccessibility bounds UAF from issue #565. Keep the visible timer Text without liveRegion so users can still focus it to hear the current value. Co-authored-by: Devil <9thLevelSoftware@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug and impact
PR #567 (#565) moved
liveRegiononto the visible rest countdownTextto avoid an iOSEXC_BAD_ACCESSfrom a zero-size accessibility node. That introduced a regression:Textstill publishes atextsemantic that updates every second, and live regions notify on text or contentDescription changes. During autoplay rest, VoiceOver/TalkBack users could receive announcements every tick (e.g. ~90 interruptions on a 90s rest), and iOS accessibility could be stressed again.Root cause
Modifier.semantics { contentDescription = lastAnnouncedText }merges withText's built-intextsemantic. Throttling onlycontentDescriptiondoes not suppress live-region events driven by the changingtextproperty.Fix
clearAndSetSemanticsso onlylastAnnouncedTextis exposed to the live region.1.dp(not0.dp) for that node to preserve the [Bug] iOS TestFlight crash during rest between sets in Compose accessibility bounds #565 iOS bounds-path fix.TextwithoutliveRegionso users can still focus it to hear the current countdown.Validation
./gradlew :shared:compileCommonMainKotlinMetadata -Pskip.supabase.check=true