cb82121ca450

stop a configuration change from locking the vault (v2.14.77)

MainActivity declares no configChanges, so a fold or unfold destroys and recreates it. The process-level background lock relies on ProcessLifecycleOwner's debounce to survive that teardown, which is timing-dependent: a foldable switching between its displays can outlast it, and the vault locks while the user is still looking at the app, producing a second lock screen and a second authentication. MainActivity now records whether its stop is a configuration change, and the background lock skips it. This makes the behaviour the existing comment already claims instead of leaving it to a race. UNVERIFIED against the reported symptom. A display-metrics change (wm size) was tried as a stand-in for the fold and does NOT reproduce it: with this guard removed the vault stayed unlocked across the same change, so an activity recreation on its own is not the trigger. The real trigger is presumed to be the display switch or a heavier teardown it causes. The guard is correct regardless — a configuration change must never lock the vault — but it is not proven to be the fix for the double lock screen. Verification: full JVM suite 1015 tests / 0 failures / 0 errors / 2 skipped; lintDebug clean; assembleDebug and debug androidTest sources compile.

time
2026-08-31 14:38 UTC · 1 month ago
machine
koh2
agent
hy4-preview
session
unfolded double lock screen
parent
b4663db939be
3 files VERSION+1 −1app/src/main/java/com/peachpasswords/MainActivity.kt+8 −0app/src/main/java/com/peachpasswords/PeachApplication.kt+14 −0
VERSION+1 −1
@@ -1 +1 @@1-2.14.761+2.14.77

view file

app/src/main/java/com/peachpasswords/MainActivity.kt+8 −0
@@ -58,6 +58,14 @@5858         lockTimer.poke()5959     }6060 61+    // Unfolding or rotating destroys and recreates this activity without the62+    // user leaving the app; record that so the process-level background lock63+    // leaves the vault alone. See PeachApplication.stopWasConfigurationChange.64+    override fun onStop() {65+        (application as PeachApplication).stopWasConfigurationChange = isChangingConfigurations()66+        super.onStop()67+    }68+6169     // launchMode="singleTask" reuses this instance across `adb shell am start`6270     // relaunches, so the QA capture-bypass extra (see onCreate) needs to be6371     // re-read here too, not just once at process start.

view file

app/src/main/java/com/peachpasswords/PeachApplication.kt+14 −0
@@ -25,6 +25,16 @@2525     @Inject lateinit var lockedSyncSpool: LockedSyncSpoolStore2626     @Inject lateinit var workerFactory: HiltWorkerFactory2727 28+    /**29+     * Set by MainActivity when its stop is a configuration change — a fold, an30+     * unfold, or a rotation — rather than a real backgrounding. ProcessLifecycleOwner31+     * is debounced, but switching a foldable between its displays can outlast that32+     * debounce, so without this the process-level stop locks a vault the user is33+     * still looking at and they meet a second lock screen drawn with the new34+     * metrics.35+     */36+    var stopWasConfigurationChange = false37+2838     override val workManagerConfiguration: Configuration2939         get() = Configuration.Builder().setWorkerFactory(workerFactory).build()3040 @@ -52,6 +62,10 @@5262                 // import flow, not a real backgrounding, so it's exempted via5363                 // VaultRepository.expectTransientBackground().5464                 if (vault.consumeTransientBackgroundSuppression()) return65+                if (stopWasConfigurationChange) {66+                    stopWasConfigurationChange = false67+                    return68+                }5569                 if (backgroundSync.enabled.value && vault.isUnlocked.value) {5670                     // Cache only opaque encrypted sync material, then perform a5771                     // real lock. The service keeps transport authority, not the

view file