[PR #6764] [MERGED] [PM-29309] [BWA-209] bug: Fix TOTP countdown freeze when returning to Authenticator app (change Flow to StateFlow) #48452

Closed
opened 2026-04-26 16:07:07 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/bitwarden/android/pull/6764
Author: @david-livefront
Created: 4/6/2026
Status: Merged
Merged: 4/6/2026
Merged by: @david-livefront

Base: mainHead: PM-29309-totp-manager


📝 Commits (1)

  • 06c4920 Fix OTP code freeze when returning to Authenticator app

📊 Changes

11 files changed (+205 additions, -78 deletions)

View changed files

📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/TotpCodeManager.kt (+4 -3)
📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/TotpCodeManagerImpl.kt (+103 -50)
📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/di/AuthenticatorManagerModule.kt (+3 -0)
📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/AuthenticatorRepositoryImpl.kt (+3 -3)
📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/model/AuthenticatorItem.kt (+11 -11)
📝 authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/util/SharedAccountDataExtensions.kt (+1 -0)
📝 authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/manager/util/TotpCodeManagerTest.kt (+52 -2)
📝 authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/manager/util/VerificationCodeItemUtil.kt (+24 -4)
📝 authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/repository/AuthenticatorRepositoryTest.kt (+1 -2)
📝 authenticator/src/test/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingViewModelTest.kt (+2 -2)
📝 authenticator/src/test/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/util/VerificationCodeItemExtensionsTest.kt (+1 -1)

📄 Description

From the original PR found here: https://github.com/bitwarden/android/pull/6246

Disclaimer: This PR was created with AI assisted agent (Claude Code) but manually checked myself to my best knowledge and this repository standards. If you feel this is against contribution guidelines (I haven't found anything related to such) feel free to disregard this PR. I honestly believe this is valid PR, and I tested it manually as well.

This fix OTP code freeze when returning to Authenticator app from background - issue #6244
when occasionally user can experience frozen TOTP codes and countdown timers when returning to the Authenticator app from background. The codes remain static and don't update until the screen is manually refreshed. This changes flow implementation in AUthenticator app (Flow) to one that is Password Manager (StateFlow).

Root Cause

The bug stems from a flow lifecycle mismatch in TotpCodeManagerImpl. The TOTP code update mechanism relies on continuous Flow emissions with a 1-second delay loop, but this flow stops when the app goes to background.

The race condition:

  1. App goes to background → collectAsStateWithLifecycle() stops collecting
  2. After 5 seconds → SharingStarted.WhileSubscribed(5_000L) stops upstream flows
  3. The delay(ONE_SECOND_MILLISECOND) timer loop stops entirely
  4. On return to foreground:
    • Collection resumes, triggering new subscription
    • Cold Flow is recreated from scratch for each item
    • Stale cached stateIn value briefly displayed before new emissions
    • Multiple items compound this as combine() waits for all flows to emit

Solution

Aligned TotpCodeManagerImpl with the Password Manager's proven pattern:

  1. Return StateFlow instead of cold Flow — Maintains current state, subscribers get immediate value
  2. Per-item StateFlow caching via mutableMapOf<AuthenticatorItem, StateFlow<...>> — Prevents flow recreation on resubscribe
  3. Per-item CoroutineScope — Each TOTP timer runs independently with proper lifecycle
  4. Removed 5-second stop timeout — Uses SharingStarted.WhileSubscribed() without delay
  5. Use SharingStarted.Eagerly for per-item flows — Ensures cached per-item flows continue emitting even when the combined flow changes (e.g., when adding new items)
  6. Explicit cleanup via onCompletion — Removes flows from cache and cancels scope when no longer needed

Changes

  • TotpCodeManager.kt — Changed return type from Flow<List<VerificationCodeItem>> to StateFlow<List<VerificationCodeItem>>
  • TotpCodeManagerImpl.kt — Added DispatcherManager dependency, per-item StateFlow caching with getOrCreateItemStateFlow(), and cleanup handlers
  • AuthenticatorManagerModule.kt — Passes dispatcherManager to TotpCodeManagerImpl constructor
  • AuthenticatorRepositoryImpl.kt — Removed 5-second timeout, now uses SharingStarted.WhileSubscribed() without delay
  • Test files — Updated mocks to use MutableStateFlow() instead of flowOf()

Testing

  • All existing unit tests pass
  • Manual testing verified:
    • Background app for 5+ seconds, return ✓
    • Background during code expiration, return ✓
    • Rotate device while showing codes ✓
    • Rapid app switching ✓

I wasn't able to recreate issue after this fix.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/bitwarden/android/pull/6764 **Author:** [@david-livefront](https://github.com/david-livefront) **Created:** 4/6/2026 **Status:** ✅ Merged **Merged:** 4/6/2026 **Merged by:** [@david-livefront](https://github.com/david-livefront) **Base:** `main` ← **Head:** `PM-29309-totp-manager` --- ### 📝 Commits (1) - [`06c4920`](https://github.com/bitwarden/android/commit/06c49208d7b59e139ce1a031073cdd7daa3c8d9e) Fix OTP code freeze when returning to Authenticator app ### 📊 Changes **11 files changed** (+205 additions, -78 deletions) <details> <summary>View changed files</summary> 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/TotpCodeManager.kt` (+4 -3) 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/TotpCodeManagerImpl.kt` (+103 -50) 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/manager/di/AuthenticatorManagerModule.kt` (+3 -0) 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/AuthenticatorRepositoryImpl.kt` (+3 -3) 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/model/AuthenticatorItem.kt` (+11 -11) 📝 `authenticator/src/main/kotlin/com/bitwarden/authenticator/data/authenticator/repository/util/SharedAccountDataExtensions.kt` (+1 -0) 📝 `authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/manager/util/TotpCodeManagerTest.kt` (+52 -2) 📝 `authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/manager/util/VerificationCodeItemUtil.kt` (+24 -4) 📝 `authenticator/src/test/kotlin/com/bitwarden/authenticator/data/authenticator/repository/AuthenticatorRepositoryTest.kt` (+1 -2) 📝 `authenticator/src/test/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/itemlisting/ItemListingViewModelTest.kt` (+2 -2) 📝 `authenticator/src/test/kotlin/com/bitwarden/authenticator/ui/authenticator/feature/util/VerificationCodeItemExtensionsTest.kt` (+1 -1) </details> ### 📄 Description From the original PR found here: https://github.com/bitwarden/android/pull/6246 Disclaimer: This PR was created with AI assisted agent (Claude Code) but manually checked myself to my best knowledge and this repository standards. If you feel this is against contribution guidelines (I haven't found anything related to such) feel free to disregard this PR. I honestly believe this is valid PR, and I tested it manually as well. This fix OTP code freeze when returning to Authenticator app from background - issue #6244 when occasionally user can experience frozen TOTP codes and countdown timers when returning to the Authenticator app from background. The codes remain static and don't update until the screen is manually refreshed. This changes flow implementation in AUthenticator app (Flow) to one that is Password Manager (StateFlow). ## Root Cause The bug stems from a flow lifecycle mismatch in `TotpCodeManagerImpl`. The TOTP code update mechanism relies on continuous Flow emissions with a 1-second delay loop, but this flow stops when the app goes to background. **The race condition:** 1. App goes to background → `collectAsStateWithLifecycle()` stops collecting 2. After 5 seconds → `SharingStarted.WhileSubscribed(5_000L)` stops upstream flows 3. The `delay(ONE_SECOND_MILLISECOND)` timer loop stops entirely 4. On return to foreground: - Collection resumes, triggering new subscription - Cold Flow is recreated from scratch for each item - Stale cached `stateIn` value briefly displayed before new emissions - Multiple items compound this as `combine()` waits for all flows to emit ## Solution Aligned `TotpCodeManagerImpl` with the Password Manager's proven pattern: 1. **Return StateFlow instead of cold Flow** — Maintains current state, subscribers get immediate value 2. **Per-item StateFlow caching** via `mutableMapOf<AuthenticatorItem, StateFlow<...>>` — Prevents flow recreation on resubscribe 3. **Per-item CoroutineScope** — Each TOTP timer runs independently with proper lifecycle 4. **Removed 5-second stop timeout** — Uses `SharingStarted.WhileSubscribed()` without delay 5. **Use `SharingStarted.Eagerly` for per-item flows** — Ensures cached per-item flows continue emitting even when the combined flow changes (e.g., when adding new items) 6. **Explicit cleanup via onCompletion** — Removes flows from cache and cancels scope when no longer needed ## Changes - **`TotpCodeManager.kt`** — Changed return type from `Flow<List<VerificationCodeItem>>` to `StateFlow<List<VerificationCodeItem>>` - **`TotpCodeManagerImpl.kt`** — Added `DispatcherManager` dependency, per-item StateFlow caching with `getOrCreateItemStateFlow()`, and cleanup handlers - **`AuthenticatorManagerModule.kt`** — Passes `dispatcherManager` to `TotpCodeManagerImpl` constructor - **`AuthenticatorRepositoryImpl.kt`** — Removed 5-second timeout, now uses `SharingStarted.WhileSubscribed()` without delay - **Test files** — Updated mocks to use `MutableStateFlow()` instead of `flowOf()` ## Testing - All existing unit tests pass - Manual testing verified: - Background app for 5+ seconds, return ✓ - Background during code expiration, return ✓ - Rotate device while showing codes ✓ - Rapid app switching ✓ I wasn't able to recreate issue after this fix. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-26 16:07:07 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/android#48452