DownloadWorker: Download required shared libs for apps
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
This commit is contained in:
@@ -2,10 +2,13 @@ package com.aurora.store.data.room
|
|||||||
|
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
|
import androidx.room.TypeConverters
|
||||||
import com.aurora.store.data.room.download.Download
|
import com.aurora.store.data.room.download.Download
|
||||||
import com.aurora.store.data.room.download.DownloadDao
|
import com.aurora.store.data.room.download.DownloadDao
|
||||||
|
import com.aurora.store.data.room.download.DownloadConverter
|
||||||
|
|
||||||
@Database(entities = [Download::class], version = 1, exportSchema = false)
|
@Database(entities = [Download::class], version = 1, exportSchema = false)
|
||||||
|
@TypeConverters(DownloadConverter::class)
|
||||||
abstract class AuroraDatabase : RoomDatabase() {
|
abstract class AuroraDatabase : RoomDatabase() {
|
||||||
abstract fun downloadDao(): DownloadDao
|
abstract fun downloadDao(): DownloadDao
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ data class Download(
|
|||||||
var speed: Long,
|
var speed: Long,
|
||||||
var timeRemaining: Long,
|
var timeRemaining: Long,
|
||||||
var totalFiles: Int,
|
var totalFiles: Int,
|
||||||
var downloadedFiles: Int
|
var downloadedFiles: Int,
|
||||||
|
val sharedLibs: List<SharedLib>
|
||||||
) : Parcelable {
|
) : Parcelable {
|
||||||
val isFinished get() = status in DownloadStatus.finished
|
val isFinished get() = status in DownloadStatus.finished
|
||||||
|
|
||||||
@@ -43,7 +44,8 @@ data class Download(
|
|||||||
0L,
|
0L,
|
||||||
0L,
|
0L,
|
||||||
0,
|
0,
|
||||||
0
|
0,
|
||||||
|
app.dependencies.dependentLibraries.map { SharedLib.fromApp(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<SharedLib> {
|
||||||
|
val listType = object : TypeToken<List<SharedLib>>() {}.type
|
||||||
|
return Gson().fromJson(string, listType)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TypeConverter
|
||||||
|
fun fromSharedLibList(list: List<SharedLib>): String {
|
||||||
|
return Gson().toJson(list)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -35,7 +35,6 @@ import kotlinx.coroutines.withContext
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import kotlinx.coroutines.NonCancellable
|
import kotlinx.coroutines.NonCancellable
|
||||||
import kotlin.io.path.ExperimentalPathApi
|
|
||||||
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
|
||||||
|
|
||||||
@@ -89,16 +88,33 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
return Result.failure()
|
return Result.failure()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Download and verify all files exists
|
// Create dirs & generate download request for files and shared libs (if any)
|
||||||
totalBytes = files.sumOf { it.size }
|
|
||||||
|
|
||||||
PathUtil.getAppDownloadDir(appContext, download.packageName, download.versionCode).mkdirs()
|
PathUtil.getAppDownloadDir(appContext, download.packageName, download.versionCode).mkdirs()
|
||||||
if (files.any { it.type == GPlayFile.FileType.OBB || it.type == GPlayFile.FileType.PATCH }) {
|
if (files.any { it.type == GPlayFile.FileType.OBB || it.type == GPlayFile.FileType.PATCH }) {
|
||||||
PathUtil.getObbDownloadDir(download.packageName).mkdirs()
|
PathUtil.getObbDownloadDir(download.packageName).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
val requestList = getDownloadRequest(files)
|
val requestList = mutableListOf<Request>()
|
||||||
|
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
|
download.totalFiles = requestList.size
|
||||||
|
totalBytes = requestList.sumOf { it.size }
|
||||||
|
|
||||||
|
// Download and verify all files exists
|
||||||
requestList.forEach { request ->
|
requestList.forEach { request ->
|
||||||
downloading = true
|
downloading = true
|
||||||
runCatching { downloadFile(request); download.downloadedFiles++ }
|
runCatching { downloadFile(request); download.downloadedFiles++ }
|
||||||
@@ -134,7 +150,6 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
return Result.success()
|
return Result.success()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalPathApi::class)
|
|
||||||
private suspend fun onFailure() {
|
private suspend fun onFailure() {
|
||||||
withContext(NonCancellable) {
|
withContext(NonCancellable) {
|
||||||
Log.i(TAG, "Cleaning up!")
|
Log.i(TAG, "Cleaning up!")
|
||||||
@@ -147,13 +162,13 @@ class DownloadWorker @AssistedInject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDownloadRequest(files: List<GPlayFile>): List<Request> {
|
private fun getDownloadRequest(files: List<GPlayFile>, libPackageName: String?): List<Request> {
|
||||||
val downloadList = mutableListOf<Request>()
|
val downloadList = mutableListOf<Request>()
|
||||||
files.filter { it.url.isNotBlank() }.forEach {
|
files.filter { it.url.isNotBlank() }.forEach {
|
||||||
val filePath = when (it.type) {
|
val filePath = when (it.type) {
|
||||||
GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> {
|
GPlayFile.FileType.BASE, GPlayFile.FileType.SPLIT -> {
|
||||||
PathUtil.getApkDownloadFile(
|
PathUtil.getApkDownloadFile(
|
||||||
appContext, download.packageName, download.versionCode, it
|
appContext, download.packageName, download.versionCode, it, libPackageName
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ fun Context.getInternalBaseDirectory(): String {
|
|||||||
|
|
||||||
object PathUtil {
|
object PathUtil {
|
||||||
|
|
||||||
|
private const val libraries = "libraries"
|
||||||
|
|
||||||
private fun getDownloadDirectory(context: Context): String {
|
private fun getDownloadDirectory(context: Context): String {
|
||||||
return if (context.isExternalStorageEnable()) {
|
return if (context.isExternalStorageEnable()) {
|
||||||
getExternalPath(context)
|
getExternalPath(context)
|
||||||
@@ -47,22 +49,45 @@ object PathUtil {
|
|||||||
private fun getVersionDirectory(
|
private fun getVersionDirectory(
|
||||||
context: Context,
|
context: Context,
|
||||||
packageName: String,
|
packageName: String,
|
||||||
versionCode: Int
|
versionCode: Int,
|
||||||
|
sharedLibPackageName: String? = null
|
||||||
): String {
|
): 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 {
|
fun getAppDownloadDir(context: Context, packageName: String, versionCode: Int): File {
|
||||||
return File(getPackageDirectory(context, packageName), versionCode.toString())
|
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(
|
fun getApkDownloadFile(
|
||||||
context: Context,
|
context: Context,
|
||||||
packageName: String,
|
packageName: String,
|
||||||
versionCode: Int,
|
versionCode: Int,
|
||||||
file: GPlayFile
|
file: GPlayFile,
|
||||||
|
sharedLibPackageName: String? = null
|
||||||
): String {
|
): 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 {
|
fun getApkDownloadFile(context: Context, packageName: String, versionCode: Int): String {
|
||||||
@@ -71,7 +96,7 @@ object PathUtil {
|
|||||||
|
|
||||||
fun getExternalPath(context: Context): String {
|
fun getExternalPath(context: Context): String {
|
||||||
val defaultDir =
|
val defaultDir =
|
||||||
java.io.File("${Environment.getExternalStorageDirectory().absolutePath}/Aurora/Store")
|
File("${Environment.getExternalStorageDirectory().absolutePath}/Aurora/Store")
|
||||||
|
|
||||||
if (!defaultDir.exists())
|
if (!defaultDir.exists())
|
||||||
defaultDir.mkdirs()
|
defaultDir.mkdirs()
|
||||||
@@ -112,8 +137,8 @@ object PathUtil {
|
|||||||
return "${context.getInternalBaseDirectory()}/SpoofConfigs"
|
return "${context.getInternalBaseDirectory()}/SpoofConfigs"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNewEmptySpoofConfig(context: Context): java.io.File {
|
fun getNewEmptySpoofConfig(context: Context): File {
|
||||||
val file = java.io.File("${getSpoofDirectory(context)}/${UUID.randomUUID()}.properties")
|
val file = File("${getSpoofDirectory(context)}/${UUID.randomUUID()}.properties")
|
||||||
file.parentFile?.mkdirs()
|
file.parentFile?.mkdirs()
|
||||||
file.createNewFile()
|
file.createNewFile()
|
||||||
return file
|
return file
|
||||||
@@ -121,9 +146,9 @@ object PathUtil {
|
|||||||
|
|
||||||
fun canWriteToDirectory(context: Context, directoryPath: String): Boolean {
|
fun canWriteToDirectory(context: Context, directoryPath: String): Boolean {
|
||||||
val directory = if (directoryPath.startsWith("/")) {
|
val directory = if (directoryPath.startsWith("/")) {
|
||||||
java.io.File(directoryPath)
|
File(directoryPath)
|
||||||
} else {
|
} else {
|
||||||
java.io.File(context.getExternalFilesDir(null), directoryPath)
|
File(context.getExternalFilesDir(null), directoryPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return if (isRAndAbove()) {
|
return if (isRAndAbove()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user