From 39b025b23599260c576d196abbda465c5844c933 Mon Sep 17 00:00:00 2001 From: Houvven <74887628+Houvven@users.noreply.github.com> Date: Wed, 20 Mar 2024 22:29:04 +0800 Subject: [PATCH] add user custom select lkm file button on install screen top bar (#1491) --- .../me/weishu/kernelsu/ui/screen/Flash.kt | 3 +- .../me/weishu/kernelsu/ui/screen/Install.kt | 44 ++++++++++++++++--- .../java/me/weishu/kernelsu/ui/util/KsuCli.kt | 19 +++++++- 3 files changed, 58 insertions(+), 8 deletions(-) diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt index aac283f3481c..099d31af6b25 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Flash.kt @@ -140,7 +140,7 @@ fun FlashScreen(navigator: DestinationsNavigator, flashIt: FlashIt) { @Parcelize sealed class FlashIt : Parcelable { - data class FlashBoot(val bootUri: Uri? = null, val ota: Boolean) : FlashIt() + data class FlashBoot(val bootUri: Uri? = null, val lkmUri: Uri? = null, val ota: Boolean) : FlashIt() data class FlashModule(val uri: Uri) : FlashIt() } @@ -153,6 +153,7 @@ fun flashIt( when (flashIt) { is FlashIt.FlashBoot -> installBoot( flashIt.bootUri, + flashIt.lkmUri, flashIt.ota, onFinish, onStdout, diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt index e50362d5308e..d9b6c7e14319 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/Install.kt @@ -3,6 +3,8 @@ package me.weishu.kernelsu.ui.screen import android.app.Activity import android.content.Intent import android.net.Uri +import android.util.Log +import android.webkit.DownloadListener import android.widget.Toast import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.result.contract.ActivityResultContracts @@ -14,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.filled.FileUpload import androidx.compose.material3.Button import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon @@ -35,8 +38,11 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.core.net.toFile import com.ramcosta.composedestinations.annotation.Destination import com.ramcosta.composedestinations.navigation.DestinationsNavigator +import com.topjohnwu.superuser.Shell +import com.topjohnwu.superuser.ShellUtils import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import me.weishu.kernelsu.R @@ -61,20 +67,41 @@ fun InstallScreen(navigator: DestinationsNavigator) { mutableStateOf(null) } + var lkmFileUri = null as Uri? + val onClickInstall = { installMethod?.let { method -> val flashIt = FlashIt.FlashBoot( - if (method is InstallMethod.SelectFile) method.uri else null, - method is InstallMethod.DirectInstallToInactiveSlot + bootUri = if (method is InstallMethod.SelectFile) method.uri else null, + lkmUri = lkmFileUri, + ota = method is InstallMethod.DirectInstallToInactiveSlot ) navigator.navigate(FlashScreenDestination(flashIt)) } } - Scaffold(topBar = { - TopBar { - navigator.popBackStack() + val selectLkmLauncher = + rememberLauncherForActivityResult(contract = ActivityResultContracts.StartActivityForResult()) { + if (it.resultCode == Activity.RESULT_OK) { + it.data?.data?.let { uri -> + lkmFileUri = uri + } + } } + + val onLkmUpload = { + selectLkmLauncher.launch( + Intent(Intent.ACTION_GET_CONTENT).apply { + type = "application/octet-stream" + } + ) + } + + Scaffold(topBar = { + TopBar( + onBack = { navigator.popBackStack() }, + onLkmUpload = onLkmUpload + ) }) { Column(modifier = Modifier.padding(it)) { SelectInstallMethod { method -> @@ -217,7 +244,7 @@ private fun SelectInstallMethod(onSelected: (InstallMethod) -> Unit = {}) { @OptIn(ExperimentalMaterial3Api::class) @Composable -private fun TopBar(onBack: () -> Unit = {}) { +private fun TopBar(onBack: () -> Unit = {}, onLkmUpload: () -> Unit = {}) { TopAppBar( title = { Text(stringResource(R.string.install)) }, navigationIcon = { @@ -225,6 +252,11 @@ private fun TopBar(onBack: () -> Unit = {}) { onClick = onBack ) { Icon(Icons.Filled.ArrowBack, contentDescription = null) } }, + actions = { + IconButton(onClick = onLkmUpload) { + Icon(Icons.Filled.FileUpload, contentDescription = null) + } + } ) } diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt index 712c3ea68f25..7fbe9ac7da3b 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/util/KsuCli.kt @@ -143,10 +143,11 @@ fun installModule( fun installBoot( bootUri: Uri?, + lkmUri: Uri?, ota: Boolean, onFinish: (Boolean) -> Unit, onStdout: (String) -> Unit, - onStderr: (String) -> Unit + onStderr: (String) -> Unit, ): Boolean { val resolver = ksuApp.contentResolver @@ -161,6 +162,17 @@ fun installBoot( } } + val lkmFile = lkmUri?.let { uri -> + with(resolver.openInputStream(uri)) { + val lkmFile = File(ksuApp.cacheDir, "kernelsu-tmp-lkm.ko") + lkmFile.outputStream().use { output -> + this?.copyTo(output) + } + + lkmFile + } + } + val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libmagiskboot.so") var cmd = "boot-patch --magiskboot ${magiskboot.absolutePath}" @@ -175,6 +187,10 @@ fun installBoot( cmd += " -u" } + lkmFile?.let { + cmd += " -m ${it.absolutePath}" + } + // output dir val downloadsDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS) @@ -200,6 +216,7 @@ fun installBoot( Log.i("KernelSU", "install boot result: ${result.isSuccess}") bootFile?.delete() + lkmFile?.delete() // if boot uri is empty, it is direct install, when success, we should show reboot button onFinish(bootUri == null && result.isSuccess)