From b7f2eaa7e3182c5e280531ce4c420479339f0cb5 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Tue, 9 Jul 2024 12:36:58 +0700 Subject: [PATCH] data: work: Add required doc-comments for all workers Signed-off-by: Aayush Gupta --- .../com/aurora/store/data/work/CacheWorker.kt | 14 +++++++ .../aurora/store/data/work/DownloadWorker.kt | 38 +++++++++++++++++++ .../aurora/store/data/work/UpdateWorker.kt | 23 +++++++++++ .../aurora/store/util/DownloadWorkerUtil.kt | 29 ++++++++++++++ 4 files changed, 104 insertions(+) diff --git a/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt b/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt index 327e1574c..cf068cfd8 100644 --- a/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/CacheWorker.kt @@ -18,6 +18,9 @@ import java.util.concurrent.TimeUnit.MINUTES import kotlin.time.DurationUnit import kotlin.time.toDuration +/** + * A periodic worker to automatically clear the old downloads cache periodically. + */ @HiltWorker class CacheWorker @AssistedInject constructor( @Assisted private val appContext: Context, @@ -28,6 +31,11 @@ class CacheWorker @AssistedInject constructor( private const val TAG = "CleanCacheWorker" private const val CLEAN_CACHE_WORKER = "CLEAN_CACHE_WORKER" + /** + * Schedules the automated cache cleanup + * @param context Current [Context] + * @see [CacheWorker] + */ fun scheduleAutomatedCacheCleanup(context: Context) { val periodicWorkRequest = PeriodicWorkRequestBuilder( repeatInterval = 1, @@ -42,6 +50,9 @@ class CacheWorker @AssistedInject constructor( } } + /** + * Duration to cache files, defaults to 6 hours + */ private val cacheDuration = 6.toDuration(DurationUnit.HOURS) override suspend fun doWork(): Result { @@ -73,6 +84,9 @@ class CacheWorker @AssistedInject constructor( return Result.success() } + /** + * Deletes the file if it's older than $[cacheDuration] + */ private fun File.deleteIfOld() { val elapsedTime = Calendar.getInstance().timeInMillis - this.lastModified() if (elapsedTime.toDuration(DurationUnit.HOURS) > cacheDuration) { diff --git a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt index 695fc1242..008865736 100644 --- a/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/DownloadWorker.kt @@ -56,6 +56,11 @@ import javax.net.ssl.HttpsURLConnection import kotlin.properties.Delegates import com.aurora.gplayapi.data.models.File as GPlayFile +/** + * An expedited long-running worker to download and trigger installation for given apps. + * + * Avoid using this worker directly and prefer using [DownloadWorkerUtil] instead. + */ @HiltWorker class DownloadWorker @AssistedInject constructor( private val downloadDao: DownloadDao, @@ -202,6 +207,13 @@ class DownloadWorker @AssistedInject constructor( } } + /** + * Purchases the app to get the download URL of the required files + * @param packageName The packageName of the app + * @param versionCode Required version of the app + * @param offerType Offer type of the app (free/paid) + * @return A list of purchased files + */ private fun purchase(packageName: String, versionCode: Int, offerType: Int): List { // Android 9.0+ supports key rotation, so purchase with latest certificate's hash return if (isPAndAbove() && download.isInstalled) { @@ -235,6 +247,12 @@ class DownloadWorker @AssistedInject constructor( return downloadList } + /** + * Downloads the file from the given request. + * Failed downloads aren't removed and persists as long as [CacheWorker] doesn't cleans them. + * @param request A [Request] to download + * @return A [Result] indicating whether the file was downloaded or not. + */ private suspend fun downloadFile(request: Request): Result { return withContext(Dispatchers.IO) { val algorithm = if (request.sha256.isBlank()) Algorithm.SHA1 else Algorithm.SHA256 @@ -278,6 +296,10 @@ class DownloadWorker @AssistedInject constructor( } } + /** + * Updates the progress data of the download in the local database and notifies user. + * @param downloadInfo An instance of [DownloadInfo] + */ private suspend fun onProgress(downloadInfo: DownloadInfo) { if (!isStopped && !download.isFinished) { downloadedBytes += downloadInfo.bytesCopied @@ -325,6 +347,11 @@ class DownloadWorker @AssistedInject constructor( } } + /** + * Notifies the user of the current status of the download. + * @param status Current [DownloadStatus] + * @param dID ID of the notification, defaults to hashCode of the download's packageName + */ private suspend fun notifyStatus(status: DownloadStatus, dID: Int = -1) { // Update status in database download.downloadStatus = status @@ -346,6 +373,13 @@ class DownloadWorker @AssistedInject constructor( notificationManager.notify(notificationID, notification) } + /** + * Validates whether given file has the expected SHA hash sum. + * @param file [File] to check + * @param expectedSha Expected SHA hash sum + * @param algorithm [Algorithm] of the SHA + * @return A boolean whether the given file has the expected SHA or not. + */ @OptIn(ExperimentalStdlibApi::class) private suspend fun validSha(file: File, expectedSha: String, algorithm: Algorithm): Boolean { return withContext(Dispatchers.IO) { @@ -362,6 +396,10 @@ class DownloadWorker @AssistedInject constructor( } } + /** + * Gets the current [Proxy] configuration. + * @return An instance of [Proxy] if configured by the user, null otherwise + */ private fun getProxy(): Proxy? { val proxyEnabled = Preferences.getBoolean(appContext, PREFERENCE_PROXY_ENABLED) val proxyInfoString = Preferences.getString(appContext, PREFERENCE_PROXY_INFO) diff --git a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt index 8add6acc9..ea6339a48 100644 --- a/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt +++ b/app/src/main/java/com/aurora/store/data/work/UpdateWorker.kt @@ -35,6 +35,11 @@ import kotlinx.coroutines.withContext import java.util.concurrent.TimeUnit.HOURS import java.util.concurrent.TimeUnit.MINUTES +/** + * A periodic worker to check for updates for installed apps based on + * filters and the auto-updates mode selected by the user. The repeat interval + * is configurable by the user, defaulting to 3 hours with a flex time of 30 minutes. + */ @HiltWorker class UpdateWorker @AssistedInject constructor( private val downloadWorkerUtil: DownloadWorkerUtil, @@ -48,17 +53,32 @@ class UpdateWorker @AssistedInject constructor( private const val TAG = "UpdateWorker" private const val UPDATE_WORKER = "UPDATE_WORKER" + /** + * Cancels the automated updates check + * @param context Current [Context] + * @see [UpdateWorker] + */ fun cancelAutomatedCheck(context: Context) { Log.i(TAG, "Cancelling periodic app updates!") WorkManager.getInstance(context).cancelUniqueWork(UPDATE_WORKER) } + /** + * Schedules the automated updates check + * @param context Current [Context] + * @see [UpdateWorker] + */ fun scheduleAutomatedCheck(context: Context) { Log.i(TAG,"Scheduling periodic app updates!") WorkManager.getInstance(context) .enqueueUniquePeriodicWork(UPDATE_WORKER, KEEP, buildUpdateWork(context)) } + /** + * Updates the automated updates check to reconsider the new user preferences + * @param context Current [Context] + * @see [UpdateWorker] + */ fun updateAutomatedCheck(context: Context) { Log.i(TAG,"Updating periodic app updates!") WorkManager.getInstance(context).updateWork(buildUpdateWork(context)) @@ -165,6 +185,9 @@ class UpdateWorker @AssistedInject constructor( return Result.success() } + /** + * Checks if the given package can be auto-updated or not + */ private fun canAutoUpdate(packageName: String): Boolean { return when (AppInstaller.getCurrentInstaller(appContext)) { Installer.SESSION -> isSAndAbove() && CertUtil.isAuroraStoreApp(appContext, packageName) diff --git a/app/src/main/java/com/aurora/store/util/DownloadWorkerUtil.kt b/app/src/main/java/com/aurora/store/util/DownloadWorkerUtil.kt index f50d900be..7fb419a25 100644 --- a/app/src/main/java/com/aurora/store/util/DownloadWorkerUtil.kt +++ b/app/src/main/java/com/aurora/store/util/DownloadWorkerUtil.kt @@ -23,6 +23,9 @@ import kotlinx.coroutines.flow.firstOrNull import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.launch +/** + * Helper class to work with the [DownloadWorker]. + */ class DownloadWorkerUtil @Inject constructor( @ApplicationContext private val context: Context, private val downloadDao: DownloadDao, @@ -44,6 +47,9 @@ class DownloadWorkerUtil @Inject constructor( private val TAG = DownloadWorkerUtil::class.java.simpleName + /** + * Removes failed download from the queue and starts observing for newly enqueued apps. + */ fun init() { AuroraApp.scope.launch { cancelFailedDownloads(downloadDao.downloads().firstOrNull() ?: emptyList()) @@ -72,10 +78,18 @@ class DownloadWorkerUtil @Inject constructor( } } + /** + * Enqueues an app for download & install + * @param app [App] to download + */ suspend fun enqueueApp(app: App) { downloadDao.insert(Download.fromApp(app)) } + /** + * Cancels the download for the given package + * @param packageName Name of the package to cancel download + */ suspend fun cancelDownload(packageName: String) { Log.i(TAG, "Cancelling download for $packageName") WorkManager.getInstance(context).cancelAllWorkByTag("$PACKAGE_NAME:$packageName") @@ -84,6 +98,11 @@ class DownloadWorkerUtil @Inject constructor( ?.let { downloadDao.updateStatus(packageName, DownloadStatus.CANCELLED) } } + /** + * Clears the entry & downloaded files for the given package + * @param packageName Name of the package of the app + * @param versionCode Version of the package + */ suspend fun clearDownload(packageName: String, versionCode: Int) { Log.i(TAG, "Clearing downloads for $packageName ($versionCode)") downloadDao.delete(packageName) @@ -91,6 +110,9 @@ class DownloadWorkerUtil @Inject constructor( .deleteRecursively() } + /** + * Clears all the downloads and their downloaded files + */ suspend fun clearAllDownloads() { Log.i(TAG, "Clearing all downloads!") downloadDao.deleteAll() @@ -98,12 +120,19 @@ class DownloadWorkerUtil @Inject constructor( PathUtil.getOldDownloadDirectories(context).forEach { it.deleteRecursively() } } + /** + * Clears finished downloads and their downloaded files + */ suspend fun clearFinishedDownloads() { downloadsList.value.filter { it.isFinished }.forEach { clearDownload(it.packageName, it.versionCode) } } + /** + * Cancels all the ongoing and queued downloads + * @param updatesOnly Whether to cancel only updates, defaults to false + */ suspend fun cancelAll(updatesOnly: Boolean = false) { // Cancel all enqueued downloads first to avoid triggering re-download downloadsList.value.filter { it.downloadStatus == DownloadStatus.QUEUED }