diff --git a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt index 7e91bfd5..e06ef0d3 100644 --- a/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt +++ b/manager/app/src/main/java/me/weishu/kernelsu/ui/screen/AppProfile.kt @@ -3,7 +3,9 @@ package me.weishu.kernelsu.ui.screen import android.util.Log import androidx.annotation.StringRes import androidx.compose.animation.Crossfade +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth @@ -20,6 +22,8 @@ import androidx.compose.material.icons.filled.ArrowDropDown import androidx.compose.material.icons.filled.ArrowDropUp import androidx.compose.material.icons.filled.Security import androidx.compose.material3.Divider +import androidx.compose.material3.DropdownMenu +import androidx.compose.material3.DropdownMenuItem import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExposedDropdownMenuBox import androidx.compose.material3.FilterChip @@ -54,6 +58,9 @@ import me.weishu.kernelsu.ui.component.SwitchItem import me.weishu.kernelsu.ui.component.profile.AppProfileConfig import me.weishu.kernelsu.ui.component.profile.RootProfileConfig import me.weishu.kernelsu.ui.util.LocalSnackbarHost +import me.weishu.kernelsu.ui.util.forceStopApp +import me.weishu.kernelsu.ui.util.launchApp +import me.weishu.kernelsu.ui.util.restartApp import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel /** @@ -77,10 +84,8 @@ fun AppProfileScreen( mutableStateOf(Natives.getAppProfile(packageName, appInfo.uid)) } - Log.i("mylog", "profile: $profile") - Scaffold( - topBar = { TopBar { navigator.popBackStack() } } + topBar = { TopBar { navigator.popBackStack() } }, ) { paddingValues -> AppProfileInner( modifier = Modifier @@ -128,11 +133,13 @@ private fun AppProfileInner( val isRootGranted = profile.allowSu Column(modifier = modifier) { - ListItem( - headlineContent = { Text(appLabel) }, - supportingContent = { Text(packageName) }, - leadingContent = appIcon, - ) + AppMenuBox(packageName) { + ListItem( + headlineContent = { Text(appLabel) }, + supportingContent = { Text(packageName) }, + leadingContent = appIcon, + ) + } SwitchItem( icon = Icons.Filled.Security, @@ -291,6 +298,51 @@ private fun ProfileBox( }) } +@Composable +private fun AppMenuBox(packageName: String, content: @Composable () -> Unit) { + + var expanded by remember { mutableStateOf(false) } + Box { + + Box(modifier = Modifier.clickable { + expanded = true + }) { + content() + } + + DropdownMenu( + expanded = expanded, + onDismissRequest = { + expanded = false + }, + ) { + DropdownMenuItem( + text = { Text(stringResource(id = R.string.launch_app)) }, + onClick = { + expanded = false + launchApp(packageName) + }, + ) + DropdownMenuItem( + text = { Text(stringResource(id = R.string.force_stop_app)) }, + onClick = { + expanded = false + forceStopApp(packageName) + }, + ) + DropdownMenuItem( + text = { Text(stringResource(id = R.string.restart_app)) }, + onClick = { + expanded = false + restartApp(packageName) + }, + ) + } + } + + +} + @Preview @Composable private fun AppProfilePreview() { 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 1a204fd0..784900aa 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 @@ -9,7 +9,6 @@ import com.topjohnwu.superuser.ShellUtils import me.weishu.kernelsu.BuildConfig import me.weishu.kernelsu.Natives import me.weishu.kernelsu.ksuApp -import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel import org.json.JSONArray import java.io.File @@ -150,4 +149,22 @@ fun isSepolicyValid(rules: String?): Boolean { val result = shell.newJob().add("ksud sepolicy check '$rules'").to(ArrayList(), null).exec() return result.isSuccess +} + +fun forceStopApp(packageName: String) { + val shell = getRootShell() + val result = shell.newJob().add("am force-stop $packageName").exec() + Log.i(TAG, "force stop $packageName result: $result") +} + +fun launchApp(packageName: String) { + + val shell = getRootShell() + val result = shell.newJob().add("monkey -p $packageName -c android.intent.category.LAUNCHER 1").exec() + Log.i(TAG, "launch $packageName result: $result") +} + +fun restartApp(packageName: String) { + forceStopApp(packageName) + launchApp(packageName) } \ No newline at end of file diff --git a/manager/app/src/main/res/values/strings.xml b/manager/app/src/main/res/values/strings.xml index a8cfc140..410581c0 100644 --- a/manager/app/src/main/res/values/strings.xml +++ b/manager/app/src/main/res/values/strings.xml @@ -80,4 +80,7 @@ Downloading module: %s Start downloading: %s New version: %s is available, click to download + Launch + Force Stop + Restart