mirror of
https://github.com/ReVanced/revanced-manager.git
synced 2026-01-20 01:33:58 +00:00
Compare commits
3 Commits
v1.26.0-de
...
feat/root-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff70a77afb | ||
|
|
c436a7a100 | ||
|
|
dbb6c01e89 |
@@ -1,3 +1,10 @@
|
|||||||
|
# app [1.26.0-dev.13](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.12...v1.26.0-dev.13) (2025-12-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* Make patcher screen design more consistent with inspiration ([#2805](https://github.com/ReVanced/revanced-manager/issues/2805)) ([dbb6c01](https://github.com/ReVanced/revanced-manager/commit/dbb6c01e89a5e710185ff4304de0ac9e19bed053))
|
||||||
|
|
||||||
# app [1.26.0-dev.12](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.11...v1.26.0-dev.12) (2025-12-17)
|
# app [1.26.0-dev.12](https://github.com/ReVanced/revanced-manager/compare/v1.26.0-dev.11...v1.26.0-dev.12) (2025-12-17)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
version = 1.26.0-dev.12
|
version = 1.26.0-dev.13
|
||||||
|
|||||||
@@ -54,7 +54,11 @@ class RootInstaller(
|
|||||||
await()
|
await()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun execute(vararg commands: String) = getShell().newJob().add(*commands).exec()
|
suspend fun execute(vararg commands: String): Shell.Result {
|
||||||
|
val stdout = mutableListOf<String>()
|
||||||
|
val stderr = mutableListOf<String>()
|
||||||
|
return getShell().newJob().add(*commands).to(stdout, stderr).exec()
|
||||||
|
}
|
||||||
|
|
||||||
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
|
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
|
||||||
|
|
||||||
@@ -108,20 +112,15 @@ class RootInstaller(
|
|||||||
unmount(packageName)
|
unmount(packageName)
|
||||||
|
|
||||||
stockAPK?.let { stockApp ->
|
stockAPK?.let { stockApp ->
|
||||||
pm.getPackageInfo(packageName)?.let { packageInfo ->
|
// TODO: get user id programmatically
|
||||||
// TODO: get user id programmatically
|
execute("pm uninstall -k --user 0 $packageName")
|
||||||
if (pm.getVersionCode(packageInfo) <= pm.getVersionCode(
|
|
||||||
pm.getPackageInfo(patchedAPK)
|
|
||||||
?: error("Failed to get package info for patched app")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
execute("pm uninstall -k --user 0 $packageName").assertSuccess("Failed to uninstall stock app")
|
|
||||||
}
|
|
||||||
|
|
||||||
execute("pm install \"${stockApp.absolutePath}\"").assertSuccess("Failed to install stock app")
|
execute("pm install -r -d --user 0 \"${stockApp.absolutePath}\"")
|
||||||
|
.assertSuccess("Failed to install stock app")
|
||||||
}
|
}
|
||||||
|
|
||||||
remoteFS.getFile(modulePath).mkdir()
|
remoteFS.getFile(modulePath).mkdirs()
|
||||||
|
.also { if (!it) throw Exception("Failed to create module directory") }
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
"service.sh",
|
"service.sh",
|
||||||
@@ -142,7 +141,6 @@ class RootInstaller(
|
|||||||
}
|
}
|
||||||
|
|
||||||
"$modulePath/$packageName.apk".let { apkPath ->
|
"$modulePath/$packageName.apk".let { apkPath ->
|
||||||
|
|
||||||
remoteFS.getFile(patchedAPK.absolutePath)
|
remoteFS.getFile(patchedAPK.absolutePath)
|
||||||
.also { if (!it.exists()) throw Exception("File doesn't exist") }
|
.also { if (!it.exists()) throw Exception("File doesn't exist") }
|
||||||
.newInputStream().use { inputStream ->
|
.newInputStream().use { inputStream ->
|
||||||
@@ -173,9 +171,43 @@ class RootInstaller(
|
|||||||
const val modulesPath = "/data/adb/modules"
|
const val modulesPath = "/data/adb/modules"
|
||||||
|
|
||||||
private fun Shell.Result.assertSuccess(errorMessage: String) {
|
private fun Shell.Result.assertSuccess(errorMessage: String) {
|
||||||
if (!isSuccess) throw Exception(errorMessage)
|
if (!isSuccess) {
|
||||||
|
throw ShellCommandException(
|
||||||
|
errorMessage,
|
||||||
|
code,
|
||||||
|
out,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ShellCommandException(
|
||||||
|
val userMessage: String,
|
||||||
|
val exitCode: Int,
|
||||||
|
val stdout: List<String>,
|
||||||
|
val stderr: List<String>
|
||||||
|
) : Exception(format(userMessage, exitCode, stdout, stderr)) {
|
||||||
|
companion object {
|
||||||
|
private fun format(message: String, exitCode: Int, stdout: List<String>, stderr: List<String>): String =
|
||||||
|
buildString {
|
||||||
|
appendLine(message)
|
||||||
|
appendLine("Exit code: $exitCode")
|
||||||
|
|
||||||
|
val output = stdout.filter { it.isNotBlank() }
|
||||||
|
val errors = stderr.filter { it.isNotBlank() }
|
||||||
|
|
||||||
|
if (output.isNotEmpty()) {
|
||||||
|
appendLine("stdout:")
|
||||||
|
output.forEach(::appendLine)
|
||||||
|
}
|
||||||
|
if (errors.isNotEmpty()) {
|
||||||
|
appendLine("stderr:")
|
||||||
|
errors.forEach(::appendLine)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class RootServiceException : Exception("Root not available")
|
class RootServiceException : Exception("Root not available")
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package app.revanced.manager.ui.component.patcher
|
package app.revanced.manager.ui.component.patcher
|
||||||
|
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.animateColorAsState
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@@ -12,7 +12,6 @@ import androidx.compose.foundation.layout.Spacer
|
|||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Cancel
|
import androidx.compose.material.icons.filled.Cancel
|
||||||
import androidx.compose.material.icons.filled.CheckCircle
|
import androidx.compose.material.icons.filled.CheckCircle
|
||||||
@@ -21,6 +20,7 @@ import androidx.compose.material3.Icon
|
|||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
@@ -53,20 +53,11 @@ fun Steps(
|
|||||||
category: StepCategory,
|
category: StepCategory,
|
||||||
steps: List<Step>,
|
steps: List<Step>,
|
||||||
stepCount: Pair<Int, Int>? = null,
|
stepCount: Pair<Int, Int>? = null,
|
||||||
stepProgressProvider: StepProgressProvider
|
stepProgressProvider: StepProgressProvider,
|
||||||
|
isExpanded: Boolean = false,
|
||||||
|
onExpand: () -> Unit,
|
||||||
|
onClick: () -> Unit
|
||||||
) {
|
) {
|
||||||
var expanded by rememberSaveable { mutableStateOf(true) }
|
|
||||||
|
|
||||||
val categoryColor by animateColorAsState(
|
|
||||||
if (expanded) MaterialTheme.colorScheme.surfaceContainerHigh else Color.Transparent,
|
|
||||||
label = "category"
|
|
||||||
)
|
|
||||||
|
|
||||||
val cardColor by animateColorAsState(
|
|
||||||
if (expanded) MaterialTheme.colorScheme.surfaceContainer else Color.Transparent,
|
|
||||||
label = "card"
|
|
||||||
)
|
|
||||||
|
|
||||||
val state = remember(steps) {
|
val state = remember(steps) {
|
||||||
when {
|
when {
|
||||||
steps.all { it.state == State.COMPLETED } -> State.COMPLETED
|
steps.all { it.state == State.COMPLETED } -> State.COMPLETED
|
||||||
@@ -76,48 +67,52 @@ fun Steps(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(state) {
|
||||||
|
if (state == State.RUNNING)
|
||||||
|
onExpand()
|
||||||
|
}
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RoundedCornerShape(16.dp))
|
.clip(MaterialTheme.shapes.large)
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.background(cardColor)
|
.background(MaterialTheme.colorScheme.surfaceContainerLow)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(14.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RoundedCornerShape(16.dp))
|
.clickable(true, onClick = onClick)
|
||||||
.clickable { expanded = !expanded }
|
.fillMaxWidth()
|
||||||
.background(categoryColor)
|
.padding(20.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
StepIcon(state = state, size = 24.dp)
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
|
||||||
modifier = Modifier.padding(16.dp)
|
|
||||||
) {
|
|
||||||
StepIcon(state = state, size = 24.dp)
|
|
||||||
|
|
||||||
Text(stringResource(category.displayName))
|
Text(stringResource(category.displayName))
|
||||||
|
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
val stepProgress = remember(stepCount, steps) {
|
val stepProgress = remember(stepCount, steps) {
|
||||||
stepCount?.let { (current, total) -> "$current/$total" }
|
stepCount?.let { (current, total) -> "$current/$total" }
|
||||||
?: "${steps.count { it.state == State.COMPLETED }}/${steps.size}"
|
?: "${steps.count { it.state == State.COMPLETED }}/${steps.size}"
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stepProgress,
|
|
||||||
style = MaterialTheme.typography.labelSmall
|
|
||||||
)
|
|
||||||
|
|
||||||
ArrowButton(modifier = Modifier.size(24.dp), expanded = expanded, onClick = null)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stepProgress,
|
||||||
|
style = MaterialTheme.typography.labelSmall
|
||||||
|
)
|
||||||
|
|
||||||
|
ArrowButton(modifier = Modifier.size(24.dp), expanded = isExpanded, onClick = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
AnimatedVisibility(visible = expanded) {
|
AnimatedVisibility(visible = isExpanded) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier
|
||||||
|
.background(MaterialTheme.colorScheme.background.copy(0.6f))
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(top = 10.dp)
|
||||||
) {
|
) {
|
||||||
steps.forEach { step ->
|
steps.forEachIndexed { index, step ->
|
||||||
val (progress, progressText) = when (step.progressKey) {
|
val (progress, progressText) = when (step.progressKey) {
|
||||||
null -> null
|
null -> null
|
||||||
ProgressKey.DOWNLOAD -> stepProgressProvider.downloadProgress?.let { (downloaded, total) ->
|
ProgressKey.DOWNLOAD -> stepProgressProvider.downloadProgress?.let { (downloaded, total) ->
|
||||||
@@ -131,7 +126,9 @@ fun Steps(
|
|||||||
state = step.state,
|
state = step.state,
|
||||||
message = step.message,
|
message = step.message,
|
||||||
progress = progress,
|
progress = progress,
|
||||||
progressText = progressText
|
progressText = progressText,
|
||||||
|
isFirst = index == 0,
|
||||||
|
isLast = index == steps.lastIndex,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -145,7 +142,9 @@ fun SubStep(
|
|||||||
state: State,
|
state: State,
|
||||||
message: String? = null,
|
message: String? = null,
|
||||||
progress: Float? = null,
|
progress: Float? = null,
|
||||||
progressText: String? = null
|
progressText: String? = null,
|
||||||
|
isFirst: Boolean = false,
|
||||||
|
isLast: Boolean = false,
|
||||||
) {
|
) {
|
||||||
var messageExpanded by rememberSaveable { mutableStateOf(true) }
|
var messageExpanded by rememberSaveable { mutableStateOf(true) }
|
||||||
|
|
||||||
@@ -156,22 +155,22 @@ fun SubStep(
|
|||||||
clickable { messageExpanded = !messageExpanded }
|
clickable { messageExpanded = !messageExpanded }
|
||||||
else this
|
else this
|
||||||
}
|
}
|
||||||
|
.padding(top = if (isFirst) 10.dp else 8.dp, bottom = if (isLast) 20.dp else 8.dp)
|
||||||
|
.padding(horizontal = 20.dp)
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 8.dp)
|
|
||||||
) {
|
) {
|
||||||
Box(
|
StepIcon(
|
||||||
modifier = Modifier.size(24.dp),
|
size = 18.dp,
|
||||||
contentAlignment = Alignment.Center
|
state = state,
|
||||||
) {
|
progress = progress,
|
||||||
StepIcon(state, progress, size = 20.dp)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = name,
|
text = name,
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.labelLarge,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier.weight(1f, true),
|
modifier = Modifier.weight(1f, true),
|
||||||
@@ -201,7 +200,7 @@ fun SubStep(
|
|||||||
text = message.orEmpty(),
|
text = message.orEmpty(),
|
||||||
style = MaterialTheme.typography.labelMedium,
|
style = MaterialTheme.typography.labelMedium,
|
||||||
color = MaterialTheme.colorScheme.secondary,
|
color = MaterialTheme.colorScheme.secondary,
|
||||||
modifier = Modifier.padding(horizontal = 52.dp, vertical = 8.dp)
|
modifier = Modifier.padding(horizontal = 36.dp, vertical = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -211,40 +210,44 @@ fun SubStep(
|
|||||||
fun StepIcon(state: State, progress: Float? = null, size: Dp) {
|
fun StepIcon(state: State, progress: Float? = null, size: Dp) {
|
||||||
val strokeWidth = Dp(floor(size.value / 10) + 1)
|
val strokeWidth = Dp(floor(size.value / 10) + 1)
|
||||||
|
|
||||||
when (state) {
|
Crossfade(targetState = state, label = "State CrossFade") { state ->
|
||||||
State.COMPLETED -> Icon(
|
when (state) {
|
||||||
Icons.Filled.CheckCircle,
|
State.COMPLETED -> Icon(
|
||||||
contentDescription = stringResource(R.string.step_completed),
|
Icons.Filled.CheckCircle,
|
||||||
tint = MaterialTheme.colorScheme.surfaceTint,
|
contentDescription = stringResource(R.string.step_completed),
|
||||||
modifier = Modifier.size(size)
|
tint = Color(0xFF59B463),
|
||||||
)
|
modifier = Modifier.size(size)
|
||||||
|
|
||||||
State.FAILED -> Icon(
|
|
||||||
Icons.Filled.Cancel,
|
|
||||||
contentDescription = stringResource(R.string.step_failed),
|
|
||||||
tint = MaterialTheme.colorScheme.error,
|
|
||||||
modifier = Modifier.size(size)
|
|
||||||
)
|
|
||||||
|
|
||||||
State.WAITING -> Icon(
|
|
||||||
Icons.Outlined.Circle,
|
|
||||||
contentDescription = stringResource(R.string.step_waiting),
|
|
||||||
tint = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
modifier = Modifier.size(size)
|
|
||||||
)
|
|
||||||
|
|
||||||
State.RUNNING ->
|
|
||||||
LoadingIndicator(
|
|
||||||
modifier = stringResource(R.string.step_running).let { description ->
|
|
||||||
Modifier
|
|
||||||
.size(size)
|
|
||||||
.semantics {
|
|
||||||
contentDescription = description
|
|
||||||
}
|
|
||||||
},
|
|
||||||
progress = { progress },
|
|
||||||
strokeWidth = strokeWidth
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
State.FAILED -> Icon(
|
||||||
|
Icons.Filled.Cancel,
|
||||||
|
contentDescription = stringResource(R.string.step_failed),
|
||||||
|
tint = MaterialTheme.colorScheme.error,
|
||||||
|
modifier = Modifier.size(size)
|
||||||
|
)
|
||||||
|
|
||||||
|
State.WAITING -> Icon(
|
||||||
|
Icons.Outlined.Circle,
|
||||||
|
contentDescription = stringResource(R.string.step_waiting),
|
||||||
|
tint = MaterialTheme.colorScheme.onSurface.copy(.2f),
|
||||||
|
modifier = Modifier.size(size)
|
||||||
|
)
|
||||||
|
|
||||||
|
State.RUNNING -> {
|
||||||
|
LoadingIndicator(
|
||||||
|
modifier = stringResource(R.string.step_running).let { description ->
|
||||||
|
Modifier
|
||||||
|
.size(size)
|
||||||
|
.semantics {
|
||||||
|
contentDescription = description
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
progress = { progress },
|
||||||
|
strokeWidth = strokeWidth
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -213,6 +213,12 @@ fun PatcherScreen(
|
|||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
|
var expandedCategory by rememberSaveable { mutableStateOf<StepCategory?>(null) }
|
||||||
|
|
||||||
|
val expandCategory: (StepCategory?) -> Unit = { category ->
|
||||||
|
expandedCategory = category
|
||||||
|
}
|
||||||
|
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
progress = { viewModel.progress },
|
progress = { viewModel.progress },
|
||||||
modifier = Modifier.fillMaxWidth()
|
modifier = Modifier.fillMaxWidth()
|
||||||
@@ -231,7 +237,12 @@ fun PatcherScreen(
|
|||||||
category = category,
|
category = category,
|
||||||
steps = steps,
|
steps = steps,
|
||||||
stepCount = if (category == StepCategory.PATCHING) viewModel.patchesProgress else null,
|
stepCount = if (category == StepCategory.PATCHING) viewModel.patchesProgress else null,
|
||||||
stepProgressProvider = viewModel
|
stepProgressProvider = viewModel,
|
||||||
|
isExpanded = expandedCategory == category,
|
||||||
|
onExpand = { expandCategory(category) },
|
||||||
|
onClick = {
|
||||||
|
expandCategory(if (expandedCategory == category) null else category)
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -377,22 +377,22 @@ class PatcherViewModel(
|
|||||||
try {
|
try {
|
||||||
isInstalling = true
|
isInstalling = true
|
||||||
|
|
||||||
val currentPackageInfo = pm.getPackageInfo(outputFile)
|
|
||||||
?: throw Exception("Failed to load application info")
|
|
||||||
|
|
||||||
// If the app is currently installed
|
|
||||||
val existingPackageInfo = pm.getPackageInfo(currentPackageInfo.packageName)
|
|
||||||
if (existingPackageInfo != null) {
|
|
||||||
// Check if the app version is less than the installed version
|
|
||||||
if (pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(existingPackageInfo)) {
|
|
||||||
// Exit if the selected app version is less than the installed version
|
|
||||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_CONFLICT
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when (installType) {
|
when (installType) {
|
||||||
InstallType.DEFAULT -> {
|
InstallType.DEFAULT -> {
|
||||||
|
val currentPackageInfo = pm.getPackageInfo(outputFile)
|
||||||
|
?: throw Exception("Failed to load application info")
|
||||||
|
|
||||||
|
// If the app is currently installed
|
||||||
|
val existingPackageInfo = pm.getPackageInfo(currentPackageInfo.packageName)
|
||||||
|
if (existingPackageInfo != null) {
|
||||||
|
// Check if the app version is less than the installed version
|
||||||
|
if (pm.getVersionCode(currentPackageInfo) < pm.getVersionCode(existingPackageInfo)) {
|
||||||
|
// Exit if the selected app version is less than the installed version
|
||||||
|
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_CONFLICT
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the app is mounted as root
|
// Check if the app is mounted as root
|
||||||
// If it is, unmount it first, silently
|
// If it is, unmount it first, silently
|
||||||
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
if (rootInstaller.hasRootAccess() && rootInstaller.isAppMounted(packageName)) {
|
||||||
@@ -412,16 +412,6 @@ class PatcherViewModel(
|
|||||||
packageInfo.label()
|
packageInfo.label()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for base APK, first check if the app is already installed
|
|
||||||
if (existingPackageInfo == null) {
|
|
||||||
// If the app is not installed, check if the output file is a base apk
|
|
||||||
if (currentPackageInfo.splitNames.isNotEmpty()) {
|
|
||||||
// Exit if there is no base APK package
|
|
||||||
packageInstallerStatus = PackageInstaller.STATUS_FAILURE_INVALID
|
|
||||||
return@launch
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val inputVersion = input.selectedApp.version
|
val inputVersion = input.selectedApp.version
|
||||||
?: inputFile?.let(pm::getPackageInfo)?.versionName
|
?: inputFile?.let(pm::getPackageInfo)?.versionName
|
||||||
?: throw Exception("Failed to determine input APK version")
|
?: throw Exception("Failed to determine input APK version")
|
||||||
|
|||||||
Reference in New Issue
Block a user