PeachApplication.kt

3.2 KB · raw

1package com.peachpasswords23import android.app.Application4import androidx.hilt.work.HiltWorkerFactory5import androidx.lifecycle.DefaultLifecycleObserver6import androidx.lifecycle.LifecycleOwner7import androidx.lifecycle.ProcessLifecycleOwner8import androidx.work.Configuration9import com.peachpasswords.sync.BackgroundSyncPreference10import com.peachpasswords.sync.ForegroundSyncCoordinator11import com.peachpasswords.sync.LockedSyncSpoolHooks12import com.peachpasswords.sync.LockedSyncSpoolStore13import com.peachpasswords.updates.UpdateCheckWorker14import com.peachpasswords.vault.VaultLockTimer15import com.peachpasswords.vault.VaultRepository16import dagger.hilt.android.HiltAndroidApp17import javax.inject.Inject1819@HiltAndroidApp20class PeachApplication : Application(), Configuration.Provider {21    @Inject lateinit var vault: VaultRepository22    @Inject lateinit var lockTimer: VaultLockTimer23    @Inject lateinit var foregroundSync: ForegroundSyncCoordinator24    @Inject lateinit var backgroundSync: BackgroundSyncPreference25    @Inject lateinit var lockedSyncSpool: LockedSyncSpoolStore26    @Inject lateinit var workerFactory: HiltWorkerFactory2728    override val workManagerConfiguration: Configuration29        get() = Configuration.Builder().setWorkerFactory(workerFactory).build()3031    override fun onCreate() {32        super.onCreate()33        LockedSyncSpoolHooks.refresh = lockedSyncSpool::refresh3435        // Update checks: once a day in the background, plus one now — process36        // start is the honest "app open". Neither ever downloads or installs;37        // the most they do is post a notification.38        UpdateCheckWorker.schedulePeriodic(this)39        UpdateCheckWorker.checkNow(this)40        // Lock the vault the moment the whole app goes to background (CF-1).41        // ProcessLifecycleOwner is process-wide and debounced, so a rotation or a42        // brief Activity restart does not trip it — only a genuine backgrounding.43        ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {44            override fun onStart(owner: LifecycleOwner) {45                foregroundSync.triggerForegroundSync()46            }4748            override fun onStop(owner: LifecycleOwner) {49                // A SAF file picker/save dialog or share sheet also stops the50                // process's activities while it's in the foreground — that's51                // an expected, momentary handoff as part of an in-app export/52                // import flow, not a real backgrounding, so it's exempted via53                // VaultRepository.expectTransientBackground().54                if (vault.consumeTransientBackgroundSuppression()) return55                if (backgroundSync.enabled.value && vault.isUnlocked.value) {56                    // Cache only opaque encrypted sync material, then perform a57                    // real lock. The service keeps transport authority, not the58                    // vault root or plaintext entries.59                    runCatching { lockedSyncSpool.refresh(vault) }60                    vault.lock()61                } else {62                    vault.lock()63                    lockTimer.cancel()64                }65            }66        })67    }68}