From 68733e1ec189ac506dfa1c1a35910387c0f12289 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Fri, 22 Mar 2024 17:53:34 +0530 Subject: [PATCH] DownloadPreference: Add a worker to regularly clear downloads cache Signed-off-by: Aayush Gupta --- .../store/data/work/CleanCacheWorker.kt | 87 +++++++++++++++++++ .../java/com/aurora/store/util/PathUtil.kt | 7 ++ .../java/com/aurora/store/util/Preferences.kt | 1 + .../view/ui/onboarding/OnboardingFragment.kt | 2 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/xml/preferences_download.xml | 14 ++- 6 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/com/aurora/store/data/work/CleanCacheWorker.kt diff --git a/app/src/main/java/com/aurora/store/data/work/CleanCacheWorker.kt b/app/src/main/java/com/aurora/store/data/work/CleanCacheWorker.kt new file mode 100644 index 000000000..e734c8ffb --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/work/CleanCacheWorker.kt @@ -0,0 +1,87 @@ +package com.aurora.store.data.work + +import android.content.Context +import android.util.Log +import androidx.hilt.work.HiltWorker +import androidx.work.CoroutineWorker +import androidx.work.ExistingPeriodicWorkPolicy.KEEP +import androidx.work.PeriodicWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.WorkerParameters +import com.aurora.store.util.PathUtil +import com.aurora.store.util.Preferences +import com.aurora.store.util.Preferences.PREFERENCE_DOWNLOADS_CACHE_TIME +import dagger.assisted.Assisted +import dagger.assisted.AssistedInject +import java.io.File +import java.util.Calendar +import java.util.concurrent.TimeUnit.HOURS +import java.util.concurrent.TimeUnit.MINUTES +import kotlin.time.DurationUnit +import kotlin.time.toDuration + +@HiltWorker +class CleanCacheWorker @AssistedInject constructor( + @Assisted private val appContext: Context, + @Assisted workerParams: WorkerParameters +) : CoroutineWorker(appContext, workerParams) { + + companion object { + private const val TAG = "CleanCacheWorker" + private const val CLEAN_CACHE_WORKER = "CLEAN_CACHE_WORKER" + + fun scheduleAutomatedCacheCleanup(context: Context) { + val periodicWorkRequest = PeriodicWorkRequestBuilder( + repeatInterval = 1, + repeatIntervalTimeUnit = HOURS, + flexTimeInterval = 30, + flexTimeIntervalUnit = MINUTES + ).build() + + Log.i(TAG, "Scheduling periodic cache cleanup!") + WorkManager.getInstance(context) + .enqueueUniquePeriodicWork(CLEAN_CACHE_WORKER, KEEP, periodicWorkRequest) + } + } + + private val cacheDuration = Preferences.getInteger(appContext, PREFERENCE_DOWNLOADS_CACHE_TIME, 6) + .toLong() + .toDuration(DurationUnit.HOURS) + + override suspend fun doWork(): Result { + Log.i(TAG, "Cleaning cache") + + PathUtil.getOldDownloadDirectories(appContext).forEach { downloadDir -> // Downloads + Log.i(TAG, "Deleting old unused download directory: $downloadDir") + downloadDir.deleteRecursively() + } + + PathUtil.getDownloadDirectory(appContext).listFiles()?.forEach { download -> // com.example.app + // Delete if the download directory is empty + if (download.listFiles().isNullOrEmpty()) { + Log.i(TAG, "Removing empty download directory for ${download.name}") + download.deleteRecursively(); return@forEach + } + + download.listFiles()!!.forEach { versionCode -> // 20240325 + if (versionCode.listFiles().isNullOrEmpty()) { + // Purge empty non-accessible directory + Log.i(TAG, "Removing empty directory for ${download.name}, ${versionCode.name}") + versionCode.deleteRecursively() + } else { + versionCode.deleteIfOld() + } + } + } + + return Result.success() + } + + private fun File.deleteIfOld() { + val elapsedTime = Calendar.getInstance().timeInMillis - this.lastModified() + if (elapsedTime.toDuration(DurationUnit.HOURS) > cacheDuration) { + Log.i(TAG, "Removing $this older than ${cacheDuration.inWholeHours} hours") + this.deleteRecursively() + } + } +} diff --git a/app/src/main/java/com/aurora/store/util/PathUtil.kt b/app/src/main/java/com/aurora/store/util/PathUtil.kt index f4c65f9a9..9650aa5df 100644 --- a/app/src/main/java/com/aurora/store/util/PathUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PathUtil.kt @@ -31,6 +31,13 @@ object PathUtil { private const val DOWNLOADS = "Downloads" private const val SPOOF = "SpoofConfigs" + fun getOldDownloadDirectories(context: Context): List { + return listOf( + File(context.filesDir, DOWNLOADS), // till 4.4.2 + File(context.getExternalFilesDir(null), DOWNLOADS) // till 4.4.2 + ) + } + fun getDownloadDirectory(context: Context): File { return File(context.cacheDir, DOWNLOADS) } diff --git a/app/src/main/java/com/aurora/store/util/Preferences.kt b/app/src/main/java/com/aurora/store/util/Preferences.kt index 097819c7e..b500207b6 100644 --- a/app/src/main/java/com/aurora/store/util/Preferences.kt +++ b/app/src/main/java/com/aurora/store/util/Preferences.kt @@ -44,6 +44,7 @@ object Preferences { const val PREFERENCE_FILTER_AURORA_ONLY = "PREFERENCE_FILTER_AURORA_ONLY" const val PREFERENCE_AUTO_INSTALL = "PREFERENCE_AUTO_INSTALL" + const val PREFERENCE_DOWNLOADS_CACHE_TIME = "PREFERENCE_DOWNLOADS_CACHE_TIME" const val PREFERENCE_AUTO_DELETE = "PREFERENCE_AUTO_DELETE" const val INSTALLATION_ABANDON_SESSION = "INSTALLATION_ABANDON_SESSION" diff --git a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt b/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt index a9c211836..945286e5d 100644 --- a/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt +++ b/app/src/main/java/com/aurora/store/view/ui/onboarding/OnboardingFragment.kt @@ -29,6 +29,7 @@ import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import com.aurora.extensions.isIgnoringBatteryOptimizations import com.aurora.store.R +import com.aurora.store.data.work.CleanCacheWorker import com.aurora.store.data.work.UpdateWorker import com.aurora.store.databinding.FragmentOnboardingBinding import com.aurora.store.util.Preferences @@ -129,6 +130,7 @@ class OnboardingFragment : Fragment(R.layout.fragment_onboarding) { binding.btnForward.isEnabled = true binding.btnForward.setOnClickListener { setupAutoUpdates() + CleanCacheWorker.scheduleAutomatedCacheCleanup(requireContext()) save(PREFERENCE_INTRO, true) findNavController().navigate( OnboardingFragmentDirections.actionOnboardingFragmentToSplashFragment() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 66c039070..2f5b58d06 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -435,4 +435,8 @@ More Manage your account + + + Keep downloads cache + How long to preserve downloads cache (failed, cancelled and completed), in hours diff --git a/app/src/main/res/xml/preferences_download.xml b/app/src/main/res/xml/preferences_download.xml index 1b62804cb..ecae6ec2a 100644 --- a/app/src/main/res/xml/preferences_download.xml +++ b/app/src/main/res/xml/preferences_download.xml @@ -17,7 +17,8 @@ ~ --> - + + +