From a09e00c7a93786477678949f21965ec8fb5fcbb2 Mon Sep 17 00:00:00 2001 From: Ax333l Date: Fri, 7 Jul 2023 12:31:31 +0200 Subject: [PATCH] fix(installer): sign and install on threads This is needed to avoid ANRs because it takes a while if the Apk is 100+ MB. --- .../ui/viewmodel/InstallerViewModel.kt | 29 +++++++++++++------ .../ui/viewmodel/UpdateProgressViewModel.kt | 2 +- .../main/java/app/revanced/manager/util/PM.kt | 2 +- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/InstallerViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/InstallerViewModel.kt index f956ba5..44484b3 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/InstallerViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/InstallerViewModel.kt @@ -15,6 +15,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import androidx.lifecycle.ViewModel import androidx.lifecycle.map +import androidx.lifecycle.viewModelScope import androidx.work.WorkInfo import androidx.work.WorkManager import app.revanced.manager.domain.manager.KeystoreManager @@ -32,8 +33,11 @@ import app.revanced.manager.util.toast import app.revanced.patcher.logging.Logger import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.toImmutableList +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.io.File @@ -146,10 +150,12 @@ class InstallerViewModel(input: Destination.Installer) : ViewModel(), KoinCompon signedFile.delete() } - private fun signApk(): Boolean { + private suspend fun signApk(): Boolean { if (!hasSigned) { try { - keystoreManager.sign(outputFile, signedFile) + withContext(Dispatchers.Default) { + keystoreManager.sign(outputFile, signedFile) + } } catch (e: Exception) { Log.e(tag, "Got exception while signing", e) app.toast(app.getString(R.string.sign_fail, e::class.simpleName)) @@ -160,22 +166,27 @@ class InstallerViewModel(input: Destination.Installer) : ViewModel(), KoinCompon return true } - fun export(uri: Uri?) = uri?.let { - if (signApk()) { - Files.copy(signedFile.toPath(), app.contentResolver.openOutputStream(it)) - app.toast(app.getString(R.string.export_app_success)) + fun export(uri: Uri?) = viewModelScope.launch { + uri?.let { + if (signApk()) { + withContext(Dispatchers.IO) { + app.contentResolver.openOutputStream(it) + .use { stream -> Files.copy(signedFile.toPath(), stream) } + } + app.toast(app.getString(R.string.export_app_success)) + } } } - fun installOrOpen() { + fun installOrOpen() = viewModelScope.launch { installedPackageName?.let { pm.launch(it) - return + return@launch } isInstalling = true try { - if (!signApk()) return + if (!signApk()) return@launch pm.installApp(listOf(signedFile)) } finally { isInstalling = false diff --git a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt index 42956ae..cf51a61 100644 --- a/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt +++ b/app/src/main/java/app/revanced/manager/ui/viewmodel/UpdateProgressViewModel.kt @@ -39,7 +39,7 @@ class UpdateProgressViewModel( } } - fun installUpdate() { + fun installUpdate() = viewModelScope.launch { pm.installApp(listOf(location)) } diff --git a/app/src/main/java/app/revanced/manager/util/PM.kt b/app/src/main/java/app/revanced/manager/util/PM.kt index 9ff1a78..83d3c39 100644 --- a/app/src/main/java/app/revanced/manager/util/PM.kt +++ b/app/src/main/java/app/revanced/manager/util/PM.kt @@ -107,7 +107,7 @@ class PM( }) } - fun installApp(apks: List) { + suspend fun installApp(apks: List) = withContext(Dispatchers.IO) { val packageInstaller = app.packageManager.packageInstaller packageInstaller.openSession(packageInstaller.createSession(sessionParams)).use { session -> apks.forEach { apk -> session.writeApk(apk) }