package com.peachpasswords import android.app.Application import androidx.hilt.work.HiltWorkerFactory import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner import androidx.work.Configuration import com.peachpasswords.sync.BackgroundSyncPreference import com.peachpasswords.sync.ForegroundSyncCoordinator import com.peachpasswords.sync.LockedSyncSpoolHooks import com.peachpasswords.sync.LockedSyncSpoolStore import com.peachpasswords.updates.UpdateCheckWorker import com.peachpasswords.vault.VaultLockTimer import com.peachpasswords.vault.VaultRepository import dagger.hilt.android.HiltAndroidApp import javax.inject.Inject @HiltAndroidApp class PeachApplication : Application(), Configuration.Provider { @Inject lateinit var vault: VaultRepository @Inject lateinit var lockTimer: VaultLockTimer @Inject lateinit var foregroundSync: ForegroundSyncCoordinator @Inject lateinit var backgroundSync: BackgroundSyncPreference @Inject lateinit var lockedSyncSpool: LockedSyncSpoolStore @Inject lateinit var workerFactory: HiltWorkerFactory override val workManagerConfiguration: Configuration get() = Configuration.Builder().setWorkerFactory(workerFactory).build() override fun onCreate() { super.onCreate() LockedSyncSpoolHooks.refresh = lockedSyncSpool::refresh // Update checks: once a day in the background, plus one now — process // start is the honest "app open". Neither ever downloads or installs; // the most they do is post a notification. UpdateCheckWorker.schedulePeriodic(this) UpdateCheckWorker.checkNow(this) // Lock the vault the moment the whole app goes to background (CF-1). // ProcessLifecycleOwner is process-wide and debounced, so a rotation or a // brief Activity restart does not trip it — only a genuine backgrounding. ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onStart(owner: LifecycleOwner) { foregroundSync.triggerForegroundSync() } override fun onStop(owner: LifecycleOwner) { // A SAF file picker/save dialog or share sheet also stops the // process's activities while it's in the foreground — that's // an expected, momentary handoff as part of an in-app export/ // import flow, not a real backgrounding, so it's exempted via // VaultRepository.expectTransientBackground(). if (vault.consumeTransientBackgroundSuppression()) return if (backgroundSync.enabled.value && vault.isUnlocked.value) { // Cache only opaque encrypted sync material, then perform a // real lock. The service keeps transport authority, not the // vault root or plaintext entries. runCatching { lockedSyncSpool.refresh(vault) } vault.lock() } else { vault.lock() lockTimer.cancel() } } }) } }