manager: Add context menu for app profile
This commit is contained in:
@@ -3,7 +3,9 @@ package me.weishu.kernelsu.ui.screen
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
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.ArrowDropUp
|
||||||
import androidx.compose.material.icons.filled.Security
|
import androidx.compose.material.icons.filled.Security
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
|
import androidx.compose.material3.DropdownMenu
|
||||||
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||||
import androidx.compose.material3.FilterChip
|
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.AppProfileConfig
|
||||||
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
|
import me.weishu.kernelsu.ui.component.profile.RootProfileConfig
|
||||||
import me.weishu.kernelsu.ui.util.LocalSnackbarHost
|
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
|
import me.weishu.kernelsu.ui.viewmodel.SuperUserViewModel
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -77,10 +84,8 @@ fun AppProfileScreen(
|
|||||||
mutableStateOf(Natives.getAppProfile(packageName, appInfo.uid))
|
mutableStateOf(Natives.getAppProfile(packageName, appInfo.uid))
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i("mylog", "profile: $profile")
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
topBar = { TopBar { navigator.popBackStack() } }
|
topBar = { TopBar { navigator.popBackStack() } },
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
AppProfileInner(
|
AppProfileInner(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -128,11 +133,13 @@ private fun AppProfileInner(
|
|||||||
val isRootGranted = profile.allowSu
|
val isRootGranted = profile.allowSu
|
||||||
|
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
|
AppMenuBox(packageName) {
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = { Text(appLabel) },
|
headlineContent = { Text(appLabel) },
|
||||||
supportingContent = { Text(packageName) },
|
supportingContent = { Text(packageName) },
|
||||||
leadingContent = appIcon,
|
leadingContent = appIcon,
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
SwitchItem(
|
SwitchItem(
|
||||||
icon = Icons.Filled.Security,
|
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
|
@Preview
|
||||||
@Composable
|
@Composable
|
||||||
private fun AppProfilePreview() {
|
private fun AppProfilePreview() {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import com.topjohnwu.superuser.ShellUtils
|
|||||||
import me.weishu.kernelsu.BuildConfig
|
import me.weishu.kernelsu.BuildConfig
|
||||||
import me.weishu.kernelsu.Natives
|
import me.weishu.kernelsu.Natives
|
||||||
import me.weishu.kernelsu.ksuApp
|
import me.weishu.kernelsu.ksuApp
|
||||||
import me.weishu.kernelsu.ui.viewmodel.ModuleViewModel
|
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -151,3 +150,21 @@ fun isSepolicyValid(rules: String?): Boolean {
|
|||||||
shell.newJob().add("ksud sepolicy check '$rules'").to(ArrayList(), null).exec()
|
shell.newJob().add("ksud sepolicy check '$rules'").to(ArrayList(), null).exec()
|
||||||
return result.isSuccess
|
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)
|
||||||
|
}
|
||||||
@@ -80,4 +80,7 @@
|
|||||||
<string name="module_downloading">Downloading module: %s</string>
|
<string name="module_downloading">Downloading module: %s</string>
|
||||||
<string name="module_start_downloading">Start downloading: %s</string>
|
<string name="module_start_downloading">Start downloading: %s</string>
|
||||||
<string name="new_version_available">New version: %s is available, click to download</string>
|
<string name="new_version_available">New version: %s is available, click to download</string>
|
||||||
|
<string name="launch_app">Launch</string>
|
||||||
|
<string name="force_stop_app">Force Stop</string>
|
||||||
|
<string name="restart_app">Restart</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
Reference in New Issue
Block a user