From 97b145e2e5340d2edf32f19027c48884401bf696 Mon Sep 17 00:00:00 2001 From: Aayush Gupta Date: Wed, 20 Dec 2023 22:16:56 +0530 Subject: [PATCH] DownloadWorker: Download required shared libs for apps Signed-off-by: Aayush Gupta --- .../aurora/store/data/room/AuroraDatabase.kt | 3 ++ .../store/data/room/download/Download.kt | 6 ++- .../data/room/download/DownloadConverter.kt | 19 ++++++++ .../store/data/room/download/SharedLib.kt | 17 ++++++++ .../aurora/store/data/work/DownloadWorker.kt | 31 +++++++++---- .../java/com/aurora/store/util/PathUtil.kt | 43 +++++++++++++++---- 6 files changed, 100 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt create mode 100644 app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt diff --git a/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt b/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt index 7da8d85ca..032805196 100644 --- a/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt +++ b/app/src/main/java/com/aurora/store/data/room/AuroraDatabase.kt @@ -2,10 +2,13 @@ package com.aurora.store.data.room import androidx.room.Database import androidx.room.RoomDatabase +import androidx.room.TypeConverters import com.aurora.store.data.room.download.Download import com.aurora.store.data.room.download.DownloadDao +import com.aurora.store.data.room.download.DownloadConverter @Database(entities = [Download::class], version = 1, exportSchema = false) +@TypeConverters(DownloadConverter::class) abstract class AuroraDatabase : RoomDatabase() { abstract fun downloadDao(): DownloadDao } diff --git a/app/src/main/java/com/aurora/store/data/room/download/Download.kt b/app/src/main/java/com/aurora/store/data/room/download/Download.kt index 386a604fa..48fc5a19b 100644 --- a/app/src/main/java/com/aurora/store/data/room/download/Download.kt +++ b/app/src/main/java/com/aurora/store/data/room/download/Download.kt @@ -23,7 +23,8 @@ data class Download( var speed: Long, var timeRemaining: Long, var totalFiles: Int, - var downloadedFiles: Int + var downloadedFiles: Int, + val sharedLibs: List ) : Parcelable { val isFinished get() = status in DownloadStatus.finished @@ -43,7 +44,8 @@ data class Download( 0L, 0L, 0, - 0 + 0, + app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) } ) } } diff --git a/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt b/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt new file mode 100644 index 000000000..37467c312 --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/room/download/DownloadConverter.kt @@ -0,0 +1,19 @@ +package com.aurora.store.data.room.download + +import androidx.room.TypeConverter +import com.google.gson.Gson +import com.google.gson.reflect.TypeToken + +object DownloadConverter { + + @TypeConverter + fun toSharedLibList(string: String): List { + val listType = object : TypeToken>() {}.type + return Gson().fromJson(string, listType) + } + + @TypeConverter + fun fromSharedLibList(list: List): String { + return Gson().toJson(list) + } +} diff --git a/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt b/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt new file mode 100644 index 000000000..1e3d3007a --- /dev/null +++ b/app/src/main/java/com/aurora/store/data/room/download/SharedLib.kt @@ -0,0 +1,17 @@ +package com.aurora.store.data.room.download + +import android.os.Parcelable +import com.aurora.gplayapi.data.models.App +import kotlinx.parcelize.Parcelize + +@Parcelize +data class SharedLib( + val packageName: String, + val versionCode: Int +) : Parcelable { + companion object { + fun fromApp(app: App): SharedLib { + return SharedLib(app.packageName, app.versionCode) + } + } +} 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 2ba64aee4..61f5ae63a 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 @@ -35,7 +35,6 @@ import kotlinx.coroutines.withContext import java.io.File import java.net.URL import kotlinx.coroutines.NonCancellable -import kotlin.io.path.ExperimentalPathApi import kotlin.properties.Delegates import com.aurora.gplayapi.data.models.File as GPlayFile @@ -89,16 +88,33 @@ class DownloadWorker @AssistedInject constructor( return Result.failure() } - // Download and verify all files exists - totalBytes = files.sumOf { it.size } - + // Create dirs & generate download request for files and shared libs (if any) PathUtil.getAppDownloadDir(appContext, download.packageName, download.versionCode).mkdirs() if (files.any { it.type == GPlayFile.FileType.OBB || it.type == GPlayFile.FileType.PATCH }) { PathUtil.getObbDownloadDir(download.packageName).mkdirs() } - val requestList = getDownloadRequest(files) + val requestList = mutableListOf() + if (download.sharedLibs.isNotEmpty()) { + // Purchase and append shared libs data to existing request + download.sharedLibs.forEach { + PathUtil.getLibDownloadDir( + appContext, + download.packageName, + download.versionCode, + it.packageName + ).mkdirs() + val libs = purchaseHelper.purchase(it.packageName, it.versionCode, 0) + requestList.addAll(getDownloadRequest(libs, it.packageName)) + } + } + requestList.addAll(getDownloadRequest(files, null)) + + // Update data for notification download.totalFiles = requestList.size + totalBytes = requestList.sumOf { it.size } + + // Download and verify all files exists requestList.forEach { request -> downloading = true runCatching { downloadFile(request); download.downloadedFiles++ } @@ -134,7 +150,6 @@ class DownloadWorker @AssistedInject constructor( return Result.success() } - @OptIn(ExperimentalPathApi::class) private suspend fun onFailure() { withContext(NonCancellable) { Log.i(TAG, "Cleaning up!") @@ -147,13 +162,13 @@ class DownloadWorker @AssistedInject constructor( } } - private fun getDownloadRequest(files: List): List { + private fun getDownloadRequest(files: List, libPackageName: String?): List { val downloadList = mutableListOf() files.filter { it.url.isNotBlank() }.forEach { val filePath = when (it.type) { GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> { PathUtil.getApkDownloadFile( - appContext, download.packageName, download.versionCode, it + appContext, download.packageName, download.versionCode, it, libPackageName ) } 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 e732672ce..d32b43721 100644 --- a/app/src/main/java/com/aurora/store/util/PathUtil.kt +++ b/app/src/main/java/com/aurora/store/util/PathUtil.kt @@ -32,6 +32,8 @@ fun Context.getInternalBaseDirectory(): String { object PathUtil { + private const val libraries = "libraries" + private fun getDownloadDirectory(context: Context): String { return if (context.isExternalStorageEnable()) { getExternalPath(context) @@ -47,22 +49,45 @@ object PathUtil { private fun getVersionDirectory( context: Context, packageName: String, - versionCode: Int + versionCode: Int, + sharedLibPackageName: String? = null ): String { - return getPackageDirectory(context, packageName) + "/$versionCode" + return if (!sharedLibPackageName.isNullOrBlank()) { + getLibDownloadDir(context, packageName, versionCode, sharedLibPackageName).absolutePath + } else { + getPackageDirectory(context, packageName) + "/$versionCode" + } } fun getAppDownloadDir(context: Context, packageName: String, versionCode: Int): File { return File(getPackageDirectory(context, packageName), versionCode.toString()) } + fun getLibDownloadDir( + context: Context, + packageName: String, + versionCode: Int, + sharedLibPackageName: String + ): File { + return File( + getAppDownloadDir(context, packageName, versionCode).absolutePath, + "$libraries/$sharedLibPackageName" + ) + } + fun getApkDownloadFile( context: Context, packageName: String, versionCode: Int, - file: GPlayFile + file: GPlayFile, + sharedLibPackageName: String? = null ): String { - return getVersionDirectory(context, packageName, versionCode) + "/${file.name}" + return getVersionDirectory( + context, + packageName, + versionCode, + sharedLibPackageName + ) + "/${file.name}" } fun getApkDownloadFile(context: Context, packageName: String, versionCode: Int): String { @@ -71,7 +96,7 @@ object PathUtil { fun getExternalPath(context: Context): String { val defaultDir = - java.io.File("${Environment.getExternalStorageDirectory().absolutePath}/Aurora/Store") + File("${Environment.getExternalStorageDirectory().absolutePath}/Aurora/Store") if (!defaultDir.exists()) defaultDir.mkdirs() @@ -112,8 +137,8 @@ object PathUtil { return "${context.getInternalBaseDirectory()}/SpoofConfigs" } - fun getNewEmptySpoofConfig(context: Context): java.io.File { - val file = java.io.File("${getSpoofDirectory(context)}/${UUID.randomUUID()}.properties") + fun getNewEmptySpoofConfig(context: Context): File { + val file = File("${getSpoofDirectory(context)}/${UUID.randomUUID()}.properties") file.parentFile?.mkdirs() file.createNewFile() return file @@ -121,9 +146,9 @@ object PathUtil { fun canWriteToDirectory(context: Context, directoryPath: String): Boolean { val directory = if (directoryPath.startsWith("/")) { - java.io.File(directoryPath) + File(directoryPath) } else { - java.io.File(context.getExternalFilesDir(null), directoryPath) + File(context.getExternalFilesDir(null), directoryPath) } return if (isRAndAbove()) {