mirror of
https://github.com/revanced/revanced-manager.git
synced 2025-04-29 21:44:26 +02:00
feat(patcher): Improve installation (#2185)
This commit is contained in:
parent
d201bdc422
commit
f6f72387b9
@ -9,7 +9,7 @@ import kotlinx.parcelize.Parcelize
|
||||
|
||||
enum class InstallType(val stringResource: Int) {
|
||||
DEFAULT(R.string.default_install),
|
||||
ROOT(R.string.root_install)
|
||||
MOUNT(R.string.mount_install)
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
@ -43,7 +43,7 @@ class RootInstaller(
|
||||
}
|
||||
}
|
||||
|
||||
return withTimeoutOrNull(Duration.ofSeconds(120L)) {
|
||||
return withTimeoutOrNull(Duration.ofSeconds(20L)) {
|
||||
remoteFS.await()
|
||||
} ?: throw RootServiceException()
|
||||
}
|
||||
@ -58,6 +58,10 @@ class RootInstaller(
|
||||
|
||||
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
|
||||
|
||||
fun isDeviceRooted() = System.getenv("PATH")?.split(":")?.any { path ->
|
||||
File(path, "su").canExecute()
|
||||
} ?: false
|
||||
|
||||
suspend fun isAppInstalled(packageName: String) =
|
||||
awaitRemoteFS().getFile("$modulesPath/$packageName-revanced").exists()
|
||||
|
||||
|
@ -135,7 +135,7 @@ class PatcherWorker(
|
||||
return try {
|
||||
if (args.input is SelectedApp.Installed) {
|
||||
installedAppRepository.get(args.packageName)?.let {
|
||||
if (it.installType == InstallType.ROOT) {
|
||||
if (it.installType == InstallType.MOUNT) {
|
||||
rootInstaller.unmount(args.packageName)
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
@ -27,7 +28,7 @@ fun InstallPickerDialog(
|
||||
AlertDialog(
|
||||
onDismissRequest = onDismiss,
|
||||
dismissButton = {
|
||||
Button(onClick = onDismiss) {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(stringResource(R.string.cancel))
|
||||
}
|
||||
},
|
||||
|
@ -81,7 +81,7 @@ fun InstalledAppInfoScreen(
|
||||
AppInfo(viewModel.appInfo) {
|
||||
Text(viewModel.installedApp.version, color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodyMedium)
|
||||
|
||||
if (viewModel.installedApp.installType == InstallType.ROOT) {
|
||||
if (viewModel.installedApp.installType == InstallType.MOUNT) {
|
||||
Text(
|
||||
text = if (viewModel.isMounted) {
|
||||
stringResource(R.string.mounted)
|
||||
@ -112,7 +112,7 @@ fun InstalledAppInfoScreen(
|
||||
onClick = viewModel::uninstall
|
||||
)
|
||||
|
||||
InstallType.ROOT -> {
|
||||
InstallType.MOUNT -> {
|
||||
SegmentedButton(
|
||||
icon = Icons.Outlined.SettingsBackupRestore,
|
||||
text = stringResource(R.string.unpatch),
|
||||
@ -138,7 +138,7 @@ fun InstalledAppInfoScreen(
|
||||
onPatchClick(viewModel.installedApp.originalPackageName, it)
|
||||
}
|
||||
},
|
||||
enabled = viewModel.installedApp.installType != InstallType.ROOT || viewModel.rootInstaller.hasRootAccess()
|
||||
enabled = viewModel.installedApp.installType != InstallType.MOUNT || viewModel.rootInstaller.hasRootAccess()
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,7 @@ import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import app.revanced.manager.R
|
||||
import app.revanced.manager.data.room.apps.installed.InstallType
|
||||
import app.revanced.manager.ui.component.AppScaffold
|
||||
import app.revanced.manager.ui.component.AppTopBar
|
||||
import app.revanced.manager.ui.component.InstallerStatusDialog
|
||||
@ -139,7 +140,8 @@ fun PatcherScreen(
|
||||
},
|
||||
onClick = {
|
||||
if (vm.installedPackageName == null)
|
||||
showInstallPicker = true
|
||||
if (vm.isDeviceRooted()) showInstallPicker = true
|
||||
else vm.install(InstallType.DEFAULT)
|
||||
else vm.open()
|
||||
}
|
||||
)
|
||||
|
@ -113,8 +113,8 @@ fun VersionSelectorScreen(
|
||||
onClick = { viewModel.select(it) },
|
||||
patchCount = supportedVersions[it.version],
|
||||
enabled =
|
||||
!(installedApp?.installType == InstallType.ROOT && !viewModel.rootInstaller.hasRootAccess()),
|
||||
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT
|
||||
!(installedApp?.installType == InstallType.MOUNT && !viewModel.rootInstaller.hasRootAccess()),
|
||||
alreadyPatched = installedApp != null && installedApp.installType != InstallType.MOUNT
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class InstalledAppInfoViewModel(
|
||||
when (installedApp.installType) {
|
||||
InstallType.DEFAULT -> pm.uninstallPackage(installedApp.currentPackageName)
|
||||
|
||||
InstallType.ROOT -> viewModelScope.launch {
|
||||
InstallType.MOUNT -> viewModelScope.launch {
|
||||
rootInstaller.uninstall(installedApp.currentPackageName)
|
||||
installedAppRepository.delete(installedApp)
|
||||
onBackClick()
|
||||
|
@ -30,7 +30,7 @@ class InstalledAppsViewModel(
|
||||
packageInfoMap[installedApp.currentPackageName] = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
if (
|
||||
installedApp.installType == InstallType.ROOT && !rootInstaller.isAppInstalled(installedApp.currentPackageName)
|
||||
installedApp.installType == InstallType.MOUNT && !rootInstaller.isAppInstalled(installedApp.currentPackageName)
|
||||
) {
|
||||
installedAppsRepository.delete(installedApp)
|
||||
return@withContext null
|
||||
@ -39,7 +39,7 @@ class InstalledAppsViewModel(
|
||||
|
||||
val packageInfo = pm.getPackageInfo(installedApp.currentPackageName)
|
||||
|
||||
if (packageInfo == null && installedApp.installType != InstallType.ROOT) {
|
||||
if (packageInfo == null && installedApp.installType != InstallType.MOUNT) {
|
||||
installedAppsRepository.delete(installedApp)
|
||||
return@withContext null
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ class PatcherViewModel(
|
||||
|
||||
override fun install() {
|
||||
// Since this is a package installer status dialog,
|
||||
// InstallType.ROOT is never used here.
|
||||
// InstallType.MOUNT is never used here.
|
||||
install(InstallType.DEFAULT)
|
||||
}
|
||||
}
|
||||
@ -230,7 +230,7 @@ class PatcherViewModel(
|
||||
app.unregisterReceiver(installerBroadcastReceiver)
|
||||
workManager.cancelWorkById(patcherWorkerId)
|
||||
|
||||
if (input.selectedApp is SelectedApp.Installed && installedApp?.installType == InstallType.ROOT) {
|
||||
if (input.selectedApp is SelectedApp.Installed && installedApp?.installType == InstallType.MOUNT) {
|
||||
GlobalScope.launch(Dispatchers.Main) {
|
||||
uiSafe(app, R.string.failed_to_mount, "Failed to mount") {
|
||||
withTimeout(Duration.ofMinutes(1L)) {
|
||||
@ -243,6 +243,8 @@ class PatcherViewModel(
|
||||
tempDir.deleteRecursively()
|
||||
}
|
||||
|
||||
fun isDeviceRooted() = rootInstaller.isDeviceRooted()
|
||||
|
||||
fun export(uri: Uri?) = viewModelScope.launch {
|
||||
uri?.let {
|
||||
withContext(Dispatchers.IO) {
|
||||
@ -301,7 +303,7 @@ class PatcherViewModel(
|
||||
pmInstallStarted = true
|
||||
}
|
||||
|
||||
InstallType.ROOT -> {
|
||||
InstallType.MOUNT -> {
|
||||
try {
|
||||
// Check for base APK, first check if the app is already installed
|
||||
if (existingPackageInfo == null) {
|
||||
@ -332,7 +334,7 @@ class PatcherViewModel(
|
||||
packageName,
|
||||
packageName,
|
||||
input.selectedApp.version,
|
||||
InstallType.ROOT,
|
||||
InstallType.MOUNT,
|
||||
input.selectedPatches
|
||||
)
|
||||
|
||||
|
@ -223,7 +223,7 @@
|
||||
<string name="applied_patches">Applied patches</string>
|
||||
<string name="view_applied_patches">View applied patches</string>
|
||||
<string name="default_install">Default</string>
|
||||
<string name="root_install">Root</string>
|
||||
<string name="mount_install">Mount</string>
|
||||
<string name="mounted">Mounted</string>
|
||||
<string name="not_mounted">Not mounted</string>
|
||||
<string name="mount">Mount</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user