data: work: Add required doc-comments for all workers
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -18,6 +18,9 @@ import java.util.concurrent.TimeUnit.MINUTES
|
|||||||
import kotlin.time.DurationUnit
|
import kotlin.time.DurationUnit
|
||||||
import kotlin.time.toDuration
|
import kotlin.time.toDuration
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A periodic worker to automatically clear the old downloads cache periodically.
|
||||||
|
*/
|
||||||
@HiltWorker
|
@HiltWorker
|
||||||
class CacheWorker @AssistedInject constructor(
|
class CacheWorker @AssistedInject constructor(
|
||||||
@Assisted private val appContext: Context,
|
@Assisted private val appContext: Context,
|
||||||
@@ -28,6 +31,11 @@ class CacheWorker @AssistedInject constructor(
|
|||||||
private const val TAG = "CleanCacheWorker"
|
private const val TAG = "CleanCacheWorker"
|
||||||
private const val CLEAN_CACHE_WORKER = "CLEAN_CACHE_WORKER"
|
private const val CLEAN_CACHE_WORKER = "CLEAN_CACHE_WORKER"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules the automated cache cleanup
|
||||||
|
* @param context Current [Context]
|
||||||
|
* @see [CacheWorker]
|
||||||
|
*/
|
||||||
fun scheduleAutomatedCacheCleanup(context: Context) {
|
fun scheduleAutomatedCacheCleanup(context: Context) {
|
||||||
val periodicWorkRequest = PeriodicWorkRequestBuilder<CacheWorker>(
|
val periodicWorkRequest = PeriodicWorkRequestBuilder<CacheWorker>(
|
||||||
repeatInterval = 1,
|
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)
|
private val cacheDuration = 6.toDuration(DurationUnit.HOURS)
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
override suspend fun doWork(): Result {
|
||||||
@@ -73,6 +84,9 @@ class CacheWorker @AssistedInject constructor(
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the file if it's older than $[cacheDuration]
|
||||||
|
*/
|
||||||
private fun File.deleteIfOld() {
|
private fun File.deleteIfOld() {
|
||||||
val elapsedTime = Calendar.getInstance().timeInMillis - this.lastModified()
|
val elapsedTime = Calendar.getInstance().timeInMillis - this.lastModified()
|
||||||
if (elapsedTime.toDuration(DurationUnit.HOURS) > cacheDuration) {
|
if (elapsedTime.toDuration(DurationUnit.HOURS) > cacheDuration) {
|
||||||
|
|||||||
@@ -56,6 +56,11 @@ import javax.net.ssl.HttpsURLConnection
|
|||||||
import kotlin.properties.Delegates
|
import kotlin.properties.Delegates
|
||||||
import com.aurora.gplayapi.data.models.File as GPlayFile
|
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
|
@HiltWorker
|
||||||
class DownloadWorker @AssistedInject constructor(
|
class DownloadWorker @AssistedInject constructor(
|
||||||
private val downloadDao: DownloadDao,
|
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<GPlayFile> {
|
private fun purchase(packageName: String, versionCode: Int, offerType: Int): List<GPlayFile> {
|
||||||
// Android 9.0+ supports key rotation, so purchase with latest certificate's hash
|
// Android 9.0+ supports key rotation, so purchase with latest certificate's hash
|
||||||
return if (isPAndAbove() && download.isInstalled) {
|
return if (isPAndAbove() && download.isInstalled) {
|
||||||
@@ -235,6 +247,12 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
return downloadList
|
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 {
|
private suspend fun downloadFile(request: Request): Result {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
val algorithm = if (request.sha256.isBlank()) Algorithm.SHA1 else Algorithm.SHA256
|
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) {
|
private suspend fun onProgress(downloadInfo: DownloadInfo) {
|
||||||
if (!isStopped && !download.isFinished) {
|
if (!isStopped && !download.isFinished) {
|
||||||
downloadedBytes += downloadInfo.bytesCopied
|
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) {
|
private suspend fun notifyStatus(status: DownloadStatus, dID: Int = -1) {
|
||||||
// Update status in database
|
// Update status in database
|
||||||
download.downloadStatus = status
|
download.downloadStatus = status
|
||||||
@@ -346,6 +373,13 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
notificationManager.notify(notificationID, notification)
|
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)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
private suspend fun validSha(file: File, expectedSha: String, algorithm: Algorithm): Boolean {
|
private suspend fun validSha(file: File, expectedSha: String, algorithm: Algorithm): Boolean {
|
||||||
return withContext(Dispatchers.IO) {
|
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? {
|
private fun getProxy(): Proxy? {
|
||||||
val proxyEnabled = Preferences.getBoolean(appContext, PREFERENCE_PROXY_ENABLED)
|
val proxyEnabled = Preferences.getBoolean(appContext, PREFERENCE_PROXY_ENABLED)
|
||||||
val proxyInfoString = Preferences.getString(appContext, PREFERENCE_PROXY_INFO)
|
val proxyInfoString = Preferences.getString(appContext, PREFERENCE_PROXY_INFO)
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ import kotlinx.coroutines.withContext
|
|||||||
import java.util.concurrent.TimeUnit.HOURS
|
import java.util.concurrent.TimeUnit.HOURS
|
||||||
import java.util.concurrent.TimeUnit.MINUTES
|
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
|
@HiltWorker
|
||||||
class UpdateWorker @AssistedInject constructor(
|
class UpdateWorker @AssistedInject constructor(
|
||||||
private val downloadWorkerUtil: DownloadWorkerUtil,
|
private val downloadWorkerUtil: DownloadWorkerUtil,
|
||||||
@@ -48,17 +53,32 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
private const val TAG = "UpdateWorker"
|
private const val TAG = "UpdateWorker"
|
||||||
private const val UPDATE_WORKER = "UPDATE_WORKER"
|
private const val UPDATE_WORKER = "UPDATE_WORKER"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancels the automated updates check
|
||||||
|
* @param context Current [Context]
|
||||||
|
* @see [UpdateWorker]
|
||||||
|
*/
|
||||||
fun cancelAutomatedCheck(context: Context) {
|
fun cancelAutomatedCheck(context: Context) {
|
||||||
Log.i(TAG, "Cancelling periodic app updates!")
|
Log.i(TAG, "Cancelling periodic app updates!")
|
||||||
WorkManager.getInstance(context).cancelUniqueWork(UPDATE_WORKER)
|
WorkManager.getInstance(context).cancelUniqueWork(UPDATE_WORKER)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedules the automated updates check
|
||||||
|
* @param context Current [Context]
|
||||||
|
* @see [UpdateWorker]
|
||||||
|
*/
|
||||||
fun scheduleAutomatedCheck(context: Context) {
|
fun scheduleAutomatedCheck(context: Context) {
|
||||||
Log.i(TAG,"Scheduling periodic app updates!")
|
Log.i(TAG,"Scheduling periodic app updates!")
|
||||||
WorkManager.getInstance(context)
|
WorkManager.getInstance(context)
|
||||||
.enqueueUniquePeriodicWork(UPDATE_WORKER, KEEP, buildUpdateWork(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) {
|
fun updateAutomatedCheck(context: Context) {
|
||||||
Log.i(TAG,"Updating periodic app updates!")
|
Log.i(TAG,"Updating periodic app updates!")
|
||||||
WorkManager.getInstance(context).updateWork(buildUpdateWork(context))
|
WorkManager.getInstance(context).updateWork(buildUpdateWork(context))
|
||||||
@@ -165,6 +185,9 @@ class UpdateWorker @AssistedInject constructor(
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given package can be auto-updated or not
|
||||||
|
*/
|
||||||
private fun canAutoUpdate(packageName: String): Boolean {
|
private fun canAutoUpdate(packageName: String): Boolean {
|
||||||
return when (AppInstaller.getCurrentInstaller(appContext)) {
|
return when (AppInstaller.getCurrentInstaller(appContext)) {
|
||||||
Installer.SESSION -> isSAndAbove() && CertUtil.isAuroraStoreApp(appContext, packageName)
|
Installer.SESSION -> isSAndAbove() && CertUtil.isAuroraStoreApp(appContext, packageName)
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ import kotlinx.coroutines.flow.firstOrNull
|
|||||||
import kotlinx.coroutines.flow.stateIn
|
import kotlinx.coroutines.flow.stateIn
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class to work with the [DownloadWorker].
|
||||||
|
*/
|
||||||
class DownloadWorkerUtil @Inject constructor(
|
class DownloadWorkerUtil @Inject constructor(
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val downloadDao: DownloadDao,
|
private val downloadDao: DownloadDao,
|
||||||
@@ -44,6 +47,9 @@ class DownloadWorkerUtil @Inject constructor(
|
|||||||
|
|
||||||
private val TAG = DownloadWorkerUtil::class.java.simpleName
|
private val TAG = DownloadWorkerUtil::class.java.simpleName
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes failed download from the queue and starts observing for newly enqueued apps.
|
||||||
|
*/
|
||||||
fun init() {
|
fun init() {
|
||||||
AuroraApp.scope.launch {
|
AuroraApp.scope.launch {
|
||||||
cancelFailedDownloads(downloadDao.downloads().firstOrNull() ?: emptyList())
|
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) {
|
suspend fun enqueueApp(app: App) {
|
||||||
downloadDao.insert(Download.fromApp(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) {
|
suspend fun cancelDownload(packageName: String) {
|
||||||
Log.i(TAG, "Cancelling download for $packageName")
|
Log.i(TAG, "Cancelling download for $packageName")
|
||||||
WorkManager.getInstance(context).cancelAllWorkByTag("$PACKAGE_NAME:$packageName")
|
WorkManager.getInstance(context).cancelAllWorkByTag("$PACKAGE_NAME:$packageName")
|
||||||
@@ -84,6 +98,11 @@ class DownloadWorkerUtil @Inject constructor(
|
|||||||
?.let { downloadDao.updateStatus(packageName, DownloadStatus.CANCELLED) }
|
?.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) {
|
suspend fun clearDownload(packageName: String, versionCode: Int) {
|
||||||
Log.i(TAG, "Clearing downloads for $packageName ($versionCode)")
|
Log.i(TAG, "Clearing downloads for $packageName ($versionCode)")
|
||||||
downloadDao.delete(packageName)
|
downloadDao.delete(packageName)
|
||||||
@@ -91,6 +110,9 @@ class DownloadWorkerUtil @Inject constructor(
|
|||||||
.deleteRecursively()
|
.deleteRecursively()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears all the downloads and their downloaded files
|
||||||
|
*/
|
||||||
suspend fun clearAllDownloads() {
|
suspend fun clearAllDownloads() {
|
||||||
Log.i(TAG, "Clearing all downloads!")
|
Log.i(TAG, "Clearing all downloads!")
|
||||||
downloadDao.deleteAll()
|
downloadDao.deleteAll()
|
||||||
@@ -98,12 +120,19 @@ class DownloadWorkerUtil @Inject constructor(
|
|||||||
PathUtil.getOldDownloadDirectories(context).forEach { it.deleteRecursively() }
|
PathUtil.getOldDownloadDirectories(context).forEach { it.deleteRecursively() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears finished downloads and their downloaded files
|
||||||
|
*/
|
||||||
suspend fun clearFinishedDownloads() {
|
suspend fun clearFinishedDownloads() {
|
||||||
downloadsList.value.filter { it.isFinished }.forEach {
|
downloadsList.value.filter { it.isFinished }.forEach {
|
||||||
clearDownload(it.packageName, it.versionCode)
|
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) {
|
suspend fun cancelAll(updatesOnly: Boolean = false) {
|
||||||
// Cancel all enqueued downloads first to avoid triggering re-download
|
// Cancel all enqueued downloads first to avoid triggering re-download
|
||||||
downloadsList.value.filter { it.downloadStatus == DownloadStatus.QUEUED }
|
downloadsList.value.filter { it.downloadStatus == DownloadStatus.QUEUED }
|
||||||
|
|||||||
Reference in New Issue
Block a user