From 9ccc81b96dc475aa19037ecfaa8b0f73cb4667e5 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 15 May 2026 15:06:13 -0300 Subject: [PATCH] Add setting to only update repos when app is opened if enabled, this auto updates repos, when user opens app and if last check was more than 12h ago --- .../org/fdroid/repo/RepoUpdateManager.kt | 13 ++++++++++ .../org/fdroid/repo/RepoUpdateWorker.kt | 2 +- .../org/fdroid/settings/SettingsConstants.kt | 9 ++++--- .../kotlin/org/fdroid/ui/settings/Settings.kt | 25 +++++++++++++------ .../org/fdroid/updates/AppUpdateWorker.kt | 2 +- app/src/main/res/values/strings.xml | 2 ++ .../org/fdroid/repo/RepoUpdateManagerTest.kt | 23 +++++++++++++++++ 7 files changed, 62 insertions(+), 14 deletions(-) diff --git a/app/src/main/kotlin/org/fdroid/repo/RepoUpdateManager.kt b/app/src/main/kotlin/org/fdroid/repo/RepoUpdateManager.kt index d03434b15..6ed95fc5b 100644 --- a/app/src/main/kotlin/org/fdroid/repo/RepoUpdateManager.kt +++ b/app/src/main/kotlin/org/fdroid/repo/RepoUpdateManager.kt @@ -23,10 +23,12 @@ import org.fdroid.download.DownloaderFactory import org.fdroid.index.IndexUpdateResult import org.fdroid.index.RepoManager import org.fdroid.index.RepoUpdater +import org.fdroid.settings.SettingsConstants import org.fdroid.settings.SettingsManager import org.fdroid.updates.UpdatesManager private const val MIN_UPDATE_INTERVAL_MILLIS = 15_000 +private const val MAX_UPDATE_INTERVAL_MILLIS = 12 * 60 * 60 * 1000L // 12 hours @Singleton class RepoUpdateManager @@ -87,6 +89,17 @@ internal constructor( workInfo?.nextScheduleTimeMillis ?: Long.MAX_VALUE } + init { + log.info { "RepoUpdateManager initialized" } + if (settingsManager.repoUpdates == SettingsConstants.AutoUpdateValues.OnlyWhenOpenApp) { + val now = System.currentTimeMillis() + if (now - settingsManager.lastRepoUpdate > MAX_UPDATE_INTERVAL_MILLIS) { + log.info { "Last repo update was more than 12h ago, triggering update..." } + RepoUpdateWorker.updateNow(context) + } + } + } + /** * Updates all enabled repositories. * diff --git a/app/src/main/kotlin/org/fdroid/repo/RepoUpdateWorker.kt b/app/src/main/kotlin/org/fdroid/repo/RepoUpdateWorker.kt index 792dd4fa8..b56f1c757 100644 --- a/app/src/main/kotlin/org/fdroid/repo/RepoUpdateWorker.kt +++ b/app/src/main/kotlin/org/fdroid/repo/RepoUpdateWorker.kt @@ -74,7 +74,7 @@ constructor( @JvmStatic fun scheduleOrCancel(context: Context, autoUpdate: AutoUpdateValues) { val workManager = WorkManager.getInstance(context) - if (autoUpdate != AutoUpdateValues.Never) { + if (autoUpdate.workerEnabled) { Log.i(TAG, "scheduleOrCancel: enqueueUniquePeriodicWork") val networkType = if (autoUpdate == AutoUpdateValues.Always) { diff --git a/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt b/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt index 51e4a0ee0..a38fd0cfe 100644 --- a/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt +++ b/app/src/main/kotlin/org/fdroid/settings/SettingsConstants.kt @@ -17,10 +17,11 @@ object SettingsConstants { const val PREF_KEY_DYNAMIC_COLORS = "dynamicColors" const val PREF_DEFAULT_DYNAMIC_COLORS = false - enum class AutoUpdateValues { - OnlyWifi, - Always, - Never, + enum class AutoUpdateValues(val workerEnabled: Boolean) { + OnlyWifi(true), + Always(true), + OnlyWhenOpenApp(false), + Never(false), } const val PREF_KEY_REPO_UPDATES = "repoAutoUpdates" diff --git a/app/src/main/kotlin/org/fdroid/ui/settings/Settings.kt b/app/src/main/kotlin/org/fdroid/ui/settings/Settings.kt index b0297444f..20ec99e3b 100644 --- a/app/src/main/kotlin/org/fdroid/ui/settings/Settings.kt +++ b/app/src/main/kotlin/org/fdroid/ui/settings/Settings.kt @@ -59,6 +59,7 @@ import org.fdroid.R import org.fdroid.settings.SettingsConstants.AutoUpdateValues import org.fdroid.settings.SettingsConstants.AutoUpdateValues.Always import org.fdroid.settings.SettingsConstants.AutoUpdateValues.Never +import org.fdroid.settings.SettingsConstants.AutoUpdateValues.OnlyWhenOpenApp import org.fdroid.settings.SettingsConstants.AutoUpdateValues.OnlyWifi import org.fdroid.settings.SettingsConstants.MirrorChooserValues import org.fdroid.settings.SettingsConstants.PREF_DEFAULT_AUTO_UPDATES @@ -214,7 +215,8 @@ fun Settings(model: SettingsModel, onSaveLogcat: (Uri?) -> Unit, onBackClicked: ) }, summary = { strValue -> - if (strValue != Never.name) { + val value = strValue.toAutoUpdateValue() + if (value.workerEnabled) { val nextUpdate = model.nextRepoUpdateFlow.collectAsState(Long.MAX_VALUE).value val nextUpdateStr = if (nextUpdate == Long.MAX_VALUE) { @@ -228,17 +230,20 @@ fun Settings(model: SettingsModel, onSaveLogcat: (Uri?) -> Unit, onBackClicked: stringResource(R.string.auto_update_time, nextUpdate.asRelativeTimeString()) } val s = - if (strValue == OnlyWifi.name) { + if (value == OnlyWifi) { stringResource(R.string.pref_repo_updates_summary_only_wifi) - } else if (strValue == Always.name) { + } else if (value == Always) { stringResource(R.string.pref_repo_updates_summary_always) } else error("Unknown value: $strValue") Text(s + "\n" + nextUpdateStr) } else { - Text( - text = stringResource(R.string.pref_repo_updates_summary_never), - color = MaterialTheme.colorScheme.error, - ) + val s = + if (value == OnlyWhenOpenApp) { + stringResource(R.string.pref_repo_updates_summary_only_when_open_app) + } else { + stringResource(R.string.pref_repo_updates_summary_never) + } + Text(text = s, color = MaterialTheme.colorScheme.error) } }, values = AutoUpdateValues.entries.map { it.name }, @@ -247,6 +252,7 @@ fun Settings(model: SettingsModel, onSaveLogcat: (Uri?) -> Unit, onBackClicked: when (value.toAutoUpdateValue()) { OnlyWifi -> res.getString(R.string.pref_auto_updates_only_wifi) Always -> res.getString(R.string.pref_auto_updates_only_always) + OnlyWhenOpenApp -> res.getString(R.string.pref_auto_updates_only_only_when_open_app) Never -> res.getString(R.string.pref_auto_updates_only_never) } ) @@ -295,12 +301,15 @@ fun Settings(model: SettingsModel, onSaveLogcat: (Uri?) -> Unit, onBackClicked: } Text(s) }, - values = AutoUpdateValues.entries.map { it.name }, + // Exclude the OnlyWhenOpenApp option here + values = + AutoUpdateValues.entries.mapNotNull { if (it == OnlyWhenOpenApp) null else it.name }, valueToText = { value: String -> AnnotatedString( when (value.toAutoUpdateValue()) { OnlyWifi -> res.getString(R.string.pref_auto_updates_only_wifi) Always -> res.getString(R.string.pref_auto_updates_only_always) + OnlyWhenOpenApp -> res.getString(R.string.pref_auto_updates_only_only_when_open_app) Never -> res.getString(R.string.pref_auto_updates_only_never) } ) diff --git a/app/src/main/kotlin/org/fdroid/updates/AppUpdateWorker.kt b/app/src/main/kotlin/org/fdroid/updates/AppUpdateWorker.kt index ae34db7ae..42892c5f0 100644 --- a/app/src/main/kotlin/org/fdroid/updates/AppUpdateWorker.kt +++ b/app/src/main/kotlin/org/fdroid/updates/AppUpdateWorker.kt @@ -49,7 +49,7 @@ constructor( @JvmStatic fun scheduleOrCancel(context: Context, autoUpdate: AutoUpdateValues) { val workManager = WorkManager.getInstance(context) - if (autoUpdate != AutoUpdateValues.Never) { + if (autoUpdate.workerEnabled) { Log.i(TAG, "scheduleOrCancel: enqueueUniquePeriodicWork") val networkType = if (autoUpdate == AutoUpdateValues.Always) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0570b9a1e..d97d5379b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -182,6 +182,7 @@ Open system language settings Only on Wi-Fi Always (even on mobile data) + Only when opening the app Never Download and update apps daily when on Wi-Fi and the device isn\'t being used Download and update apps daily even on mobile data when the device isn\'t being used @@ -189,6 +190,7 @@ Check for updates Periodically fetch app updates from repositories only when on Wi-Fi Periodically fetch app updates from repositories even when on mobile data + Check for updates only when opened • Apps will become outdated Don\'t check for updates • Apps will become outdated Network Download mirror selection diff --git a/app/src/test/java/org/fdroid/repo/RepoUpdateManagerTest.kt b/app/src/test/java/org/fdroid/repo/RepoUpdateManagerTest.kt index b59469dbe..ca40f229b 100644 --- a/app/src/test/java/org/fdroid/repo/RepoUpdateManagerTest.kt +++ b/app/src/test/java/org/fdroid/repo/RepoUpdateManagerTest.kt @@ -29,6 +29,7 @@ import org.fdroid.index.IndexUpdateResult import org.fdroid.index.RepoManager import org.fdroid.index.RepoUpdater import org.fdroid.install.InstalledAppsCache +import org.fdroid.settings.SettingsConstants import org.fdroid.settings.SettingsManager import org.fdroid.updates.AppUpdateWorker import org.fdroid.updates.UpdatesManager @@ -57,6 +58,7 @@ internal class RepoUpdateManagerTest { every { db.getRepositoryDao() } returns repositoryDao every { context.getString(any(), any()) } returns "repo update" every { settingsManager.isFirstStart } returns false + every { settingsManager.repoUpdates } returns SettingsConstants.AutoUpdateValues.OnlyWifi every { installedAppsCache.installedApps } returns MutableStateFlow(emptyMap()) } @@ -324,6 +326,27 @@ internal class RepoUpdateManagerTest { } } + @Test + fun `triggers updateNow on init when OnlyWhenOpenApp and last update is stale`() { + every { settingsManager.repoUpdates } returns SettingsConstants.AutoUpdateValues.OnlyWhenOpenApp + every { settingsManager.lastRepoUpdate } returns 0L + every { RepoUpdateWorker.updateNow(any()) } just runs + + RepoUpdateManager( + context = context, + db = db, + repoManager = repoManager, + updatesManager = updatesManager, + settingsManager = settingsManager, + downloaderFactory = mockk(relaxed = true), + notificationManager = notificationManager, + compatibilityChecker = compatibilityChecker, + repoUpdater = repoUpdater, + ) + + verify(exactly = 1) { RepoUpdateWorker.updateNow(context) } + } + /** * Workaround for [verify] calls trying to take installedAppsCache into account for * [UpdatesManager.loadUpdates].