Skip to content

Prevent Sync Failure When App is in the Background#3836

Open
qiarie wants to merge 6 commits into
fix/debug-mode-detection-and-echis-updatesfrom
fix-sync-when-app-is-in-the-background
Open

Prevent Sync Failure When App is in the Background#3836
qiarie wants to merge 6 commits into
fix/debug-mode-detection-and-echis-updatesfrom
fix-sync-when-app-is-in-the-background

Conversation

@qiarie

@qiarie qiarie commented Mar 26, 2026

Copy link
Copy Markdown
Contributor

On Android 12+ (API 31+), calling setForeground() while the app is in the background throws ForegroundServiceStartNotAllowedException. Previously, this call was grouped with the sync logic, causing the entire worker to fail and stop progressing if the periodic sync triggered while the app was not in the foreground.

Changes:

  • Isolated setForeground() in an independent runCatching block to ensure sync proceeds even if the foreground notification cannot be started.
  • Refactored doWork() to use a try-catch block for more robust exception handling and proper result propagation.

IMPORTANT: Where possible all PRs must be linked to a Github issue

Fixes [link to issue]

Engineer Checklist

  • I have written Unit tests for any new feature(s) and edge cases for bug fixes
  • I have added any strings visible on UI components to the strings.xml file
  • I have updated the CHANGELOG.md file for any notable changes to the codebase
  • I have run ./gradlew spotlessApply and ./gradlew spotlessCheck to check my code follows the project's style guide
  • I have built and run the FHIRCore app to verify my change fixes the issue and/or does not break the app
  • I have checked that this PR does NOT introduce breaking changes that require an update to Content and/or Configs? If it does add a sample here or a link to exactly what changes need to be made to the content.

Code Reviewer Checklist

  • I have verified Unit tests have been written for any new feature(s) and edge cases
  • I have verified any strings visible on UI components are in the strings.xml file
  • I have verifed the CHANGELOG.md file has any notable changes to the codebase
  • I have verified the solution has been implemented in a configurable and generic way for reuseable components
  • I have built and run the FHIRCore app to verify the change fixes the issue and/or does not break the app

On Android 12+ (API 31+), calling setForeground() while the app is in
the background throws ForegroundServiceStartNotAllowedException.
Previously, this call was grouped with the sync logic, causing the
entire worker to fail and stop progressing if the periodic sync
triggered while the app was not in the foreground.

Changes:
- Isolated setForeground() in an independent runCatching block to
  ensure sync proceeds even if the foreground notification cannot
  be started.
- Refactored doWork() to use a try-catch block for more robust
  exception handling and proper result propagation.
@qiarie qiarie changed the title fix: prevent sync failure when app is in background Prevent Sync Failure When App is in the Background Mar 26, 2026
allan-on and others added 5 commits May 6, 2026 12:33
* ⬆️ Update FHIR SDK dependencies

* ⬇️ Downgrade SDK dependencies

Downgraded barcode, locationwidget and sdk-data-capture versions

* ⬆️ Upgrade Kujaku lib
* Add version info to the output APK filename

* Remove lingering sync overlay scrim on low-resource devices

After initial sync hits 100% the progress dialog content disappears but its full-screen scrim could remain on screen, blocking all touch and rendering the app unusable. On fast devices this is invisible; on slower devices the orphaned scrim is long-lived or permanent, and appears to persist across app restarts.

Root cause: LoaderDialog had two unsynchronized dismiss paths. LoaderContent self-hid its content via a SideEffect at >=100% (during the Running phase), but the Compose Dialog window - and its scrim - was only torn down when the caller's isFirstTimeSync flag flipped to false on terminal Succeeded. The gap between the two left an empty, touch-blocking dim layer, and the isFirstTimeSync recompute was itself fragile (cross-listener ordering, a stale record-count read, and coupling to data presence rather than to sync completion).

Drive dialog dismissal from a single authoritative signal:

- LoaderDialog: drop LoaderContent's local openDialog state and the 100% SideEffect so content and Dialog window appear and disappear together, gated solely by the caller
- RegisterScreen: gate the dialog on isFirstTimeSync && !syncTerminated, where syncTerminated covers terminal CurrentSyncJobStatus (Succeeded or Failed), so the scrim is torn down on the same event delivered to all listeners
- RegisterViewModel: recompute isFirstTimeSync after the register count resolves (re-emit RegisterUiState from inside the count coroutine) to remove the stale-count race

* Comments cleanup

* Remove BaseVariantOutputImpl qualified import

* Run spotlessApply
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants