feat(patcher): Improve installation (#2185)

This commit is contained in:
alieRN 2024-09-19 22:17:38 +03:00 committed by GitHub
parent d201bdc422
commit f6f72387b9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 27 additions and 18 deletions

View File

@ -9,7 +9,7 @@ import kotlinx.parcelize.Parcelize
enum class InstallType(val stringResource: Int) { enum class InstallType(val stringResource: Int) {
DEFAULT(R.string.default_install), DEFAULT(R.string.default_install),
ROOT(R.string.root_install) MOUNT(R.string.mount_install)
} }
@Parcelize @Parcelize

View File

@ -43,7 +43,7 @@ class RootInstaller(
} }
} }
return withTimeoutOrNull(Duration.ofSeconds(120L)) { return withTimeoutOrNull(Duration.ofSeconds(20L)) {
remoteFS.await() remoteFS.await()
} ?: throw RootServiceException() } ?: throw RootServiceException()
} }
@ -58,6 +58,10 @@ class RootInstaller(
fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false fun hasRootAccess() = Shell.isAppGrantedRoot() ?: false
fun isDeviceRooted() = System.getenv("PATH")?.split(":")?.any { path ->
File(path, "su").canExecute()
} ?: false
suspend fun isAppInstalled(packageName: String) = suspend fun isAppInstalled(packageName: String) =
awaitRemoteFS().getFile("$modulesPath/$packageName-revanced").exists() awaitRemoteFS().getFile("$modulesPath/$packageName-revanced").exists()

View File

@ -135,7 +135,7 @@ class PatcherWorker(
return try { return try {
if (args.input is SelectedApp.Installed) { if (args.input is SelectedApp.Installed) {
installedAppRepository.get(args.packageName)?.let { installedAppRepository.get(args.packageName)?.let {
if (it.installType == InstallType.ROOT) { if (it.installType == InstallType.MOUNT) {
rootInstaller.unmount(args.packageName) rootInstaller.unmount(args.packageName)
} }
} }

View File

@ -7,6 +7,7 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ListItem import androidx.compose.material3.ListItem
import androidx.compose.material3.RadioButton import androidx.compose.material3.RadioButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
@ -27,7 +28,7 @@ fun InstallPickerDialog(
AlertDialog( AlertDialog(
onDismissRequest = onDismiss, onDismissRequest = onDismiss,
dismissButton = { dismissButton = {
Button(onClick = onDismiss) { TextButton(onClick = onDismiss) {
Text(stringResource(R.string.cancel)) Text(stringResource(R.string.cancel))
} }
}, },

View File

@ -81,7 +81,7 @@ fun InstalledAppInfoScreen(
AppInfo(viewModel.appInfo) { AppInfo(viewModel.appInfo) {
Text(viewModel.installedApp.version, color = MaterialTheme.colorScheme.onSurfaceVariant, style = MaterialTheme.typography.bodyMedium) 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(
text = if (viewModel.isMounted) { text = if (viewModel.isMounted) {
stringResource(R.string.mounted) stringResource(R.string.mounted)
@ -112,7 +112,7 @@ fun InstalledAppInfoScreen(
onClick = viewModel::uninstall onClick = viewModel::uninstall
) )
InstallType.ROOT -> { InstallType.MOUNT -> {
SegmentedButton( SegmentedButton(
icon = Icons.Outlined.SettingsBackupRestore, icon = Icons.Outlined.SettingsBackupRestore,
text = stringResource(R.string.unpatch), text = stringResource(R.string.unpatch),
@ -138,7 +138,7 @@ fun InstalledAppInfoScreen(
onPatchClick(viewModel.installedApp.originalPackageName, it) onPatchClick(viewModel.installedApp.originalPackageName, it)
} }
}, },
enabled = viewModel.installedApp.installType != InstallType.ROOT || viewModel.rootInstaller.hasRootAccess() enabled = viewModel.installedApp.installType != InstallType.MOUNT || viewModel.rootInstaller.hasRootAccess()
) )
} }

View File

@ -38,6 +38,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import app.revanced.manager.R 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.AppScaffold
import app.revanced.manager.ui.component.AppTopBar import app.revanced.manager.ui.component.AppTopBar
import app.revanced.manager.ui.component.InstallerStatusDialog import app.revanced.manager.ui.component.InstallerStatusDialog
@ -139,7 +140,8 @@ fun PatcherScreen(
}, },
onClick = { onClick = {
if (vm.installedPackageName == null) if (vm.installedPackageName == null)
showInstallPicker = true if (vm.isDeviceRooted()) showInstallPicker = true
else vm.install(InstallType.DEFAULT)
else vm.open() else vm.open()
} }
) )

View File

@ -113,8 +113,8 @@ fun VersionSelectorScreen(
onClick = { viewModel.select(it) }, onClick = { viewModel.select(it) },
patchCount = supportedVersions[it.version], patchCount = supportedVersions[it.version],
enabled = enabled =
!(installedApp?.installType == InstallType.ROOT && !viewModel.rootInstaller.hasRootAccess()), !(installedApp?.installType == InstallType.MOUNT && !viewModel.rootInstaller.hasRootAccess()),
alreadyPatched = installedApp != null && installedApp.installType != InstallType.ROOT alreadyPatched = installedApp != null && installedApp.installType != InstallType.MOUNT
) )
} }
} }

View File

@ -78,7 +78,7 @@ class InstalledAppInfoViewModel(
when (installedApp.installType) { when (installedApp.installType) {
InstallType.DEFAULT -> pm.uninstallPackage(installedApp.currentPackageName) InstallType.DEFAULT -> pm.uninstallPackage(installedApp.currentPackageName)
InstallType.ROOT -> viewModelScope.launch { InstallType.MOUNT -> viewModelScope.launch {
rootInstaller.uninstall(installedApp.currentPackageName) rootInstaller.uninstall(installedApp.currentPackageName)
installedAppRepository.delete(installedApp) installedAppRepository.delete(installedApp)
onBackClick() onBackClick()

View File

@ -30,7 +30,7 @@ class InstalledAppsViewModel(
packageInfoMap[installedApp.currentPackageName] = withContext(Dispatchers.IO) { packageInfoMap[installedApp.currentPackageName] = withContext(Dispatchers.IO) {
try { try {
if ( if (
installedApp.installType == InstallType.ROOT && !rootInstaller.isAppInstalled(installedApp.currentPackageName) installedApp.installType == InstallType.MOUNT && !rootInstaller.isAppInstalled(installedApp.currentPackageName)
) { ) {
installedAppsRepository.delete(installedApp) installedAppsRepository.delete(installedApp)
return@withContext null return@withContext null
@ -39,7 +39,7 @@ class InstalledAppsViewModel(
val packageInfo = pm.getPackageInfo(installedApp.currentPackageName) val packageInfo = pm.getPackageInfo(installedApp.currentPackageName)
if (packageInfo == null && installedApp.installType != InstallType.ROOT) { if (packageInfo == null && installedApp.installType != InstallType.MOUNT) {
installedAppsRepository.delete(installedApp) installedAppsRepository.delete(installedApp)
return@withContext null return@withContext null
} }

View File

@ -77,7 +77,7 @@ class PatcherViewModel(
override fun install() { override fun install() {
// Since this is a package installer status dialog, // Since this is a package installer status dialog,
// InstallType.ROOT is never used here. // InstallType.MOUNT is never used here.
install(InstallType.DEFAULT) install(InstallType.DEFAULT)
} }
} }
@ -230,7 +230,7 @@ class PatcherViewModel(
app.unregisterReceiver(installerBroadcastReceiver) app.unregisterReceiver(installerBroadcastReceiver)
workManager.cancelWorkById(patcherWorkerId) 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) { GlobalScope.launch(Dispatchers.Main) {
uiSafe(app, R.string.failed_to_mount, "Failed to mount") { uiSafe(app, R.string.failed_to_mount, "Failed to mount") {
withTimeout(Duration.ofMinutes(1L)) { withTimeout(Duration.ofMinutes(1L)) {
@ -243,6 +243,8 @@ class PatcherViewModel(
tempDir.deleteRecursively() tempDir.deleteRecursively()
} }
fun isDeviceRooted() = rootInstaller.isDeviceRooted()
fun export(uri: Uri?) = viewModelScope.launch { fun export(uri: Uri?) = viewModelScope.launch {
uri?.let { uri?.let {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
@ -301,7 +303,7 @@ class PatcherViewModel(
pmInstallStarted = true pmInstallStarted = true
} }
InstallType.ROOT -> { InstallType.MOUNT -> {
try { try {
// Check for base APK, first check if the app is already installed // Check for base APK, first check if the app is already installed
if (existingPackageInfo == null) { if (existingPackageInfo == null) {
@ -332,7 +334,7 @@ class PatcherViewModel(
packageName, packageName,
packageName, packageName,
input.selectedApp.version, input.selectedApp.version,
InstallType.ROOT, InstallType.MOUNT,
input.selectedPatches input.selectedPatches
) )

View File

@ -223,7 +223,7 @@
<string name="applied_patches">Applied patches</string> <string name="applied_patches">Applied patches</string>
<string name="view_applied_patches">View applied patches</string> <string name="view_applied_patches">View applied patches</string>
<string name="default_install">Default</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="mounted">Mounted</string>
<string name="not_mounted">Not mounted</string> <string name="not_mounted">Not mounted</string>
<string name="mount">Mount</string> <string name="mount">Mount</string>