Merge branch 'dev' of https://github.com/ShirkNeko/SukiSU-Ultra into dev
This commit is contained in:
@@ -9,7 +9,7 @@ import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -29,11 +29,7 @@ import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import com.maxkeppeker.sheets.core.models.base.Header
|
||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||
import com.maxkeppeler.sheets.list.ListDialog
|
||||
import com.maxkeppeler.sheets.list.models.ListOption
|
||||
import com.maxkeppeler.sheets.list.models.ListSelection
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
|
||||
@@ -43,6 +39,9 @@ import shirkneko.zako.sukisu.R
|
||||
import shirkneko.zako.sukisu.ui.component.DialogHandle
|
||||
import shirkneko.zako.sukisu.ui.component.rememberConfirmDialog
|
||||
import shirkneko.zako.sukisu.ui.component.rememberCustomDialog
|
||||
import shirkneko.zako.sukisu.ui.theme.ThemeConfig
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardColors
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardElevation
|
||||
import shirkneko.zako.sukisu.ui.util.*
|
||||
import shirkneko.zako.sukisu.utils.AssetsUtil
|
||||
import java.io.File
|
||||
@@ -500,35 +499,79 @@ fun rememberSelectKmiDialog(onSelected: (String?) -> Unit): DialogHandle {
|
||||
val supportedKmi by produceState(initialValue = emptyList<String>()) {
|
||||
value = getSupportedKmis()
|
||||
}
|
||||
val options = supportedKmi.map { value ->
|
||||
val listOptions = supportedKmi.map { value ->
|
||||
ListOption(
|
||||
titleText = value
|
||||
titleText = value,
|
||||
subtitleText = null,
|
||||
icon = null
|
||||
)
|
||||
}
|
||||
|
||||
var selection by remember { mutableStateOf<String?>(null) }
|
||||
Box(
|
||||
modifier = Modifier.background(MaterialTheme.colorScheme.surface)
|
||||
) {
|
||||
ListDialog(
|
||||
state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
onSelected(selection)
|
||||
}, onCloseRequest = {
|
||||
dismiss()
|
||||
}),
|
||||
header = Header.Default(
|
||||
title = stringResource(R.string.select_kmi),
|
||||
),
|
||||
selection = ListSelection.Single(
|
||||
showRadioButtons = true,
|
||||
options = options,
|
||||
) { _, option ->
|
||||
selection = option.titleText
|
||||
var selection: String? = null
|
||||
val cardColor = if (!ThemeConfig.useDynamicColor) {
|
||||
ThemeConfig.currentTheme.ButtonContrast
|
||||
} else {
|
||||
MaterialTheme.colorScheme.secondaryContainer
|
||||
}
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.select_kmi))
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
listOptions.forEachIndexed { index, option ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
selection = supportedKmi[index]
|
||||
}
|
||||
.padding(vertical = 8.dp)
|
||||
) {
|
||||
Column {
|
||||
Text(text = option.titleText)
|
||||
option.subtitleText?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (selection != null) {
|
||||
onSelected(selection)
|
||||
}
|
||||
dismiss()
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
dismiss()
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
containerColor = getCardColors(cardColor.copy(alpha = 0.9f)).containerColor.copy(alpha = 0.9f),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
tonalElevation = getCardElevation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
||||
@@ -20,9 +20,11 @@ import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.Undo
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalBottomSheet
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
@@ -49,12 +51,9 @@ import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.core.content.FileProvider
|
||||
import com.maxkeppeker.sheets.core.models.base.Header
|
||||
import androidx.core.content.edit
|
||||
import com.maxkeppeker.sheets.core.models.base.IconSource
|
||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||
import com.maxkeppeler.sheets.list.ListDialog
|
||||
import com.maxkeppeler.sheets.list.models.ListOption
|
||||
import com.maxkeppeler.sheets.list.models.ListSelection
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
|
||||
@@ -75,14 +74,14 @@ import shirkneko.zako.sukisu.ui.component.SwitchItem
|
||||
import shirkneko.zako.sukisu.ui.component.rememberConfirmDialog
|
||||
import shirkneko.zako.sukisu.ui.component.rememberCustomDialog
|
||||
import shirkneko.zako.sukisu.ui.component.rememberLoadingDialog
|
||||
import shirkneko.zako.sukisu.ui.theme.CardConfig
|
||||
import shirkneko.zako.sukisu.ui.theme.ThemeConfig
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardColors
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardElevation
|
||||
import shirkneko.zako.sukisu.ui.util.LocalSnackbarHost
|
||||
import shirkneko.zako.sukisu.ui.util.getBugreportFile
|
||||
import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import androidx.compose.material.icons.filled.ExpandMore
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import shirkneko.zako.sukisu.ui.theme.CardConfig
|
||||
import androidx.core.content.edit
|
||||
|
||||
|
||||
/**
|
||||
@@ -111,7 +110,6 @@ fun SettingScreen(navigator: DestinationsNavigator) {
|
||||
AboutDialog(it)
|
||||
}
|
||||
val loadingDialog = rememberLoadingDialog()
|
||||
val shrinkDialog = rememberConfirmDialog()
|
||||
// endregion
|
||||
|
||||
Column(
|
||||
@@ -451,20 +449,73 @@ fun rememberUninstallDialog(onSelected: (UninstallType) -> Unit): DialogHandle {
|
||||
}
|
||||
|
||||
var selection = UninstallType.NONE
|
||||
ListDialog(state = rememberUseCaseState(visible = true, onFinishedRequest = {
|
||||
val cardColor = if (!ThemeConfig.useDynamicColor) {
|
||||
ThemeConfig.currentTheme.ButtonContrast
|
||||
} else {
|
||||
MaterialTheme.colorScheme.secondaryContainer
|
||||
}
|
||||
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
},
|
||||
title = {
|
||||
Text(text = stringResource(R.string.settings_uninstall))
|
||||
},
|
||||
text = {
|
||||
Column {
|
||||
listOptions.forEachIndexed { index, option ->
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
selection = options[index]
|
||||
}
|
||||
.padding(vertical = 8.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = options[index].icon,
|
||||
contentDescription = null,
|
||||
modifier = Modifier.padding(end = 8.dp)
|
||||
)
|
||||
Column {
|
||||
Text(text = option.titleText)
|
||||
option.subtitleText?.let {
|
||||
Text(
|
||||
text = it,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
androidx.compose.material3.TextButton(
|
||||
onClick = {
|
||||
if (selection != UninstallType.NONE) {
|
||||
onSelected(selection)
|
||||
}
|
||||
}, onCloseRequest = {
|
||||
dismiss()
|
||||
}), header = Header.Default(
|
||||
title = stringResource(R.string.settings_uninstall),
|
||||
), selection = ListSelection.Single(
|
||||
showRadioButtons = false,
|
||||
options = listOptions,
|
||||
) { index, _ ->
|
||||
selection = options[index]
|
||||
})
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(android.R.string.ok))
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
androidx.compose.material3.TextButton(
|
||||
onClick = {
|
||||
dismiss()
|
||||
}
|
||||
) {
|
||||
Text(text = stringResource(android.R.string.cancel))
|
||||
}
|
||||
},
|
||||
containerColor = getCardColors(cardColor.copy(alpha = 0.9f)).containerColor.copy(alpha = 0.9f),
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
tonalElevation = getCardElevation()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@ import shirkneko.zako.sukisu.R
|
||||
import shirkneko.zako.sukisu.ui.component.ConfirmResult
|
||||
import shirkneko.zako.sukisu.ui.component.SearchAppBar
|
||||
import shirkneko.zako.sukisu.ui.component.rememberConfirmDialog
|
||||
import shirkneko.zako.sukisu.ui.component.rememberLoadingDialog
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardColors
|
||||
import shirkneko.zako.sukisu.ui.theme.getCardElevation
|
||||
import shirkneko.zako.sukisu.ui.viewmodel.KpmViewModel
|
||||
@@ -38,6 +37,10 @@ import shirkneko.zako.sukisu.ui.util.unloadKpmModule
|
||||
import java.io.File
|
||||
import androidx.core.content.edit
|
||||
import shirkneko.zako.sukisu.ui.theme.ThemeConfig
|
||||
import shirkneko.zako.sukisu.ui.component.rememberCustomDialog
|
||||
import shirkneko.zako.sukisu.ui.component.ConfirmDialogHandle
|
||||
import java.net.URLDecoder
|
||||
import java.net.URLEncoder
|
||||
|
||||
/**
|
||||
* KPM 管理界面
|
||||
@@ -55,7 +58,6 @@ fun KpmScreen(
|
||||
val scope = rememberCoroutineScope()
|
||||
val snackBarHost = remember { SnackbarHostState() }
|
||||
val confirmDialog = rememberConfirmDialog()
|
||||
val loadingDialog = rememberLoadingDialog()
|
||||
val cardColor = if (!ThemeConfig.useDynamicColor) {
|
||||
ThemeConfig.currentTheme.ButtonContrast
|
||||
} else {
|
||||
@@ -64,17 +66,86 @@ fun KpmScreen(
|
||||
|
||||
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||
|
||||
val kpmInstall = stringResource(R.string.kpm_install)
|
||||
val kpmInstallConfirm = stringResource(R.string.kpm_install_confirm)
|
||||
val kpmInstallSuccess = stringResource(R.string.kpm_install_success)
|
||||
val kpmInstallFailed = stringResource(R.string.kpm_install_failed)
|
||||
val install = stringResource(R.string.install)
|
||||
val cancel = stringResource(R.string.cancel)
|
||||
val kpmUninstall = stringResource(R.string.kpm_uninstall)
|
||||
val kpmUninstallConfirmTemplate = stringResource(R.string.kpm_uninstall_confirm)
|
||||
val uninstall = stringResource(R.string.uninstall)
|
||||
val FailedtoCheckModuleFile = stringResource(R.string.snackbar_failed_to_check_module_file)
|
||||
val kpmUninstallSuccess = stringResource(R.string.kpm_uninstall_success)
|
||||
val kpmUninstallFailed = stringResource(R.string.kpm_uninstall_failed)
|
||||
val kpmInstallMode = stringResource(R.string.kpm_install_mode)
|
||||
val kpmInstallModeLoad = stringResource(R.string.kpm_install_mode_load)
|
||||
val kpmInstallModeEmbed = stringResource(R.string.kpm_install_mode_embed)
|
||||
val kpmInstallModeDescription = stringResource(R.string.kpm_install_mode_description)
|
||||
|
||||
var tempFileForInstall by remember { mutableStateOf<File?>(null) }
|
||||
val installModeDialog = rememberCustomDialog { dismiss ->
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
dismiss()
|
||||
tempFileForInstall?.delete()
|
||||
tempFileForInstall = null
|
||||
},
|
||||
title = { Text(kpmInstallMode) },
|
||||
text = { Text(kpmInstallModeDescription) },
|
||||
confirmButton = {
|
||||
Column {
|
||||
Button(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
dismiss()
|
||||
tempFileForInstall?.let { tempFile ->
|
||||
handleModuleInstall(
|
||||
tempFile = tempFile,
|
||||
isEmbed = false,
|
||||
viewModel = viewModel,
|
||||
snackBarHost = snackBarHost,
|
||||
kpmInstallSuccess = kpmInstallSuccess,
|
||||
kpmInstallFailed = kpmInstallFailed
|
||||
)
|
||||
}
|
||||
tempFileForInstall = null
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(kpmInstallModeLoad)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Button(
|
||||
onClick = {
|
||||
scope.launch {
|
||||
dismiss()
|
||||
tempFileForInstall?.let { tempFile ->
|
||||
handleModuleInstall(
|
||||
tempFile = tempFile,
|
||||
isEmbed = true,
|
||||
viewModel = viewModel,
|
||||
snackBarHost = snackBarHost,
|
||||
kpmInstallSuccess = kpmInstallSuccess,
|
||||
kpmInstallFailed = kpmInstallFailed
|
||||
)
|
||||
}
|
||||
tempFileForInstall = null
|
||||
}
|
||||
}
|
||||
) {
|
||||
Text(kpmInstallModeEmbed)
|
||||
}
|
||||
}
|
||||
},
|
||||
dismissButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
dismiss()
|
||||
tempFileForInstall?.delete()
|
||||
tempFileForInstall = null
|
||||
}
|
||||
) {
|
||||
Text(cancel)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val selectPatchLauncher = rememberLauncherForActivityResult(
|
||||
contract = ActivityResultContracts.StartActivityForResult()
|
||||
@@ -84,8 +155,10 @@ fun KpmScreen(
|
||||
val uri = result.data?.data ?: return@rememberLauncherForActivityResult
|
||||
|
||||
scope.launch {
|
||||
// 复制文件到临时目录
|
||||
val tempFile = File(context.cacheDir, "temp_patch.kpm")
|
||||
val fileName = uri.lastPathSegment ?: "unknown.kpm"
|
||||
val encodedFileName = URLEncoder.encode(fileName, "UTF-8")
|
||||
val tempFile = File(context.cacheDir, encodedFileName)
|
||||
|
||||
context.contentResolver.openInputStream(uri)?.use { input ->
|
||||
tempFile.outputStream().use { output ->
|
||||
input.copyTo(output)
|
||||
@@ -101,43 +174,8 @@ fun KpmScreen(
|
||||
return@launch
|
||||
}
|
||||
|
||||
val confirmResult = confirmDialog.awaitConfirm(
|
||||
title = kpmInstall,
|
||||
content = kpmInstallConfirm,
|
||||
confirm = install,
|
||||
dismiss = cancel
|
||||
)
|
||||
|
||||
if (confirmResult == ConfirmResult.Confirmed) {
|
||||
val success = loadingDialog.withLoading {
|
||||
try {
|
||||
val loadResult = loadKpmModule(tempFile.absolutePath)
|
||||
if (true && loadResult.startsWith("Error")) {
|
||||
Log.e("KsuCli", "Failed to load KPM module: $loadResult")
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to load KPM module: ${e.message}", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
viewModel.fetchModuleList()
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallSuccess,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
} else {
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
}
|
||||
}
|
||||
tempFile.delete()
|
||||
tempFileForInstall = tempFile
|
||||
installModeDialog.show()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,46 +272,21 @@ fun KpmScreen(
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
items(viewModel.moduleList) { module ->
|
||||
val kpmUninstallConfirm = String.format(kpmUninstallConfirmTemplate, module.name)
|
||||
KpmModuleItem(
|
||||
module = module,
|
||||
onUninstall = {
|
||||
scope.launch {
|
||||
val confirmResult = confirmDialog.awaitConfirm(
|
||||
title = kpmUninstall,
|
||||
content = kpmUninstallConfirm,
|
||||
confirm = uninstall,
|
||||
dismiss = cancel
|
||||
handleModuleUninstall(
|
||||
module = module,
|
||||
viewModel = viewModel,
|
||||
snackBarHost = snackBarHost,
|
||||
kpmUninstallSuccess = kpmUninstallSuccess,
|
||||
kpmUninstallFailed = kpmUninstallFailed,
|
||||
FailedtoCheckModuleFile = FailedtoCheckModuleFile,
|
||||
uninstall = uninstall,
|
||||
cancel = cancel,
|
||||
confirmDialog = confirmDialog
|
||||
)
|
||||
if (confirmResult == ConfirmResult.Confirmed) {
|
||||
val success = loadingDialog.withLoading {
|
||||
try {
|
||||
val unloadResult = unloadKpmModule(module.id)
|
||||
if (true && unloadResult.startsWith("Error")) {
|
||||
Log.e("KsuCli", "Failed to unload KPM module: $unloadResult")
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to unload KPM module: ${e.message}", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
if (success) {
|
||||
viewModel.fetchModuleList()
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmUninstallSuccess,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
} else {
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmUninstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onControl = {
|
||||
@@ -287,6 +300,133 @@ fun KpmScreen(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleModuleInstall(
|
||||
tempFile: File,
|
||||
isEmbed: Boolean,
|
||||
viewModel: KpmViewModel,
|
||||
snackBarHost: SnackbarHostState,
|
||||
kpmInstallSuccess: String,
|
||||
kpmInstallFailed: String
|
||||
) {
|
||||
val moduleId = extractModuleId(tempFile.name)
|
||||
if (moduleId == null) {
|
||||
Log.e("KsuCli", "Failed to extract module ID from file: ${tempFile.name}")
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
tempFile.delete()
|
||||
return
|
||||
}
|
||||
|
||||
val targetPath = "/data/adb/kpm/$moduleId.kpm"
|
||||
|
||||
try {
|
||||
if (isEmbed) {
|
||||
Runtime.getRuntime().exec(arrayOf("su", "-c", "mkdir -p /data/adb/kpm")).waitFor()
|
||||
Runtime.getRuntime().exec(arrayOf("su", "-c", "cp ${tempFile.absolutePath} $targetPath")).waitFor()
|
||||
}
|
||||
|
||||
val loadResult = loadKpmModule(tempFile.absolutePath)
|
||||
if (loadResult.startsWith("Error")) {
|
||||
Log.e("KsuCli", "Failed to load KPM module: $loadResult")
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
} else {
|
||||
viewModel.fetchModuleList()
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallSuccess,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to load KPM module: ${e.message}", e)
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmInstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
}
|
||||
tempFile.delete()
|
||||
}
|
||||
|
||||
private fun extractModuleId(fileName: String): String? {
|
||||
return try {
|
||||
val decodedFileName = URLDecoder.decode(fileName, "UTF-8")
|
||||
val pattern = "([^/]*?)\\.kpm$".toRegex()
|
||||
val matchResult = pattern.find(decodedFileName)
|
||||
matchResult?.groupValues?.get(1)
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to extract module ID: ${e.message}", e)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun handleModuleUninstall(
|
||||
module: KpmViewModel.ModuleInfo,
|
||||
viewModel: KpmViewModel,
|
||||
snackBarHost: SnackbarHostState,
|
||||
kpmUninstallSuccess: String,
|
||||
kpmUninstallFailed: String,
|
||||
FailedtoCheckModuleFile: String,
|
||||
uninstall: String,
|
||||
cancel: String,
|
||||
confirmDialog: ConfirmDialogHandle
|
||||
) {
|
||||
val moduleFileName = "${module.id}.kpm"
|
||||
val moduleFilePath = "/data/adb/kpm/$moduleFileName"
|
||||
|
||||
val fileExists = try {
|
||||
val result = Runtime.getRuntime().exec(arrayOf("su", "-c", "ls /data/adb/kpm/$moduleFileName")).waitFor() == 0
|
||||
result
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to check module file existence: ${e.message}", e)
|
||||
snackBarHost.showSnackbar(
|
||||
message = FailedtoCheckModuleFile,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
false
|
||||
}
|
||||
|
||||
val confirmResult = confirmDialog.awaitConfirm(
|
||||
title = "将卸载以下kpm模块:\n$moduleFileName",
|
||||
content = "The following kpm modules will be uninstalled:\n$moduleFileName",
|
||||
confirm = uninstall,
|
||||
dismiss = cancel
|
||||
)
|
||||
|
||||
if (confirmResult == ConfirmResult.Confirmed) {
|
||||
try {
|
||||
val unloadResult = unloadKpmModule(module.id)
|
||||
if (unloadResult.startsWith("Error")) {
|
||||
Log.e("KsuCli", "Failed to unload KPM module: $unloadResult")
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmUninstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
if (fileExists) {
|
||||
Runtime.getRuntime().exec(arrayOf("su", "-c", "rm $moduleFilePath")).waitFor()
|
||||
}
|
||||
|
||||
viewModel.fetchModuleList()
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmUninstallSuccess,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Log.e("KsuCli", "Failed to unload KPM module: ${e.message}", e)
|
||||
snackBarHost.showSnackbar(
|
||||
message = kpmUninstallFailed,
|
||||
duration = SnackbarDuration.Short
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun KpmModuleItem(
|
||||
module: KpmViewModel.ModuleInfo,
|
||||
|
||||
@@ -8,26 +8,32 @@
|
||||
<string name="home_superuser_count">スーパーユーザー: %d</string>
|
||||
<string name="home_module_count">モジュール: %d</string>
|
||||
<string name="home_unsupported">非対応</string>
|
||||
<string name="home_unsupported_reason">現在、 KernelSU は GKI カーネルにのみ対応しています</string>
|
||||
<string name="home_unsupported_reason">カーネルの KernelSU ドライバが未検出です。カーネルが間違ってませんか?</string>
|
||||
<string name="home_kernel">カーネル</string>
|
||||
<string name="home_manager_version">アプリのバージョン</string>
|
||||
<string name="home_susfs">SuSFS: %s</string>
|
||||
<string name="home_susfs_version">SuSFS のバージョン</string>
|
||||
<string name="home_susfs_sus_su">SuS SU</string>
|
||||
<string name="home_manager_version">マネージャーのバージョン</string>
|
||||
<string name="home_fingerprint">Fingerprint</string>
|
||||
<string name="home_selinux_status">SELinux の状態</string>
|
||||
<string name="selinux_status_disabled">Disabled</string>
|
||||
<string name="home_selinux_status">SELinux のステータス</string>
|
||||
<string name="selinux_status_disabled">無効</string>
|
||||
<string name="selinux_status_enforcing">Enforcing</string>
|
||||
<string name="selinux_status_permissive">Permissive</string>
|
||||
<string name="selinux_status_unknown">不明</string>
|
||||
<string name="superuser">スーパーユーザー</string>
|
||||
<string name="module_failed_to_enable">%s モジュールをオンにできませんでした</string>
|
||||
<string name="module_failed_to_disable">%s モジュールをオフにできませんでした</string>
|
||||
<string name="module_failed_to_enable">%s モジュールを ON にできませんでした</string>
|
||||
<string name="module_failed_to_disable">%s モジュールを OFF にできませんでした</string>
|
||||
<string name="module_empty">モジュールがインストールされていません</string>
|
||||
<string name="module">モジュール</string>
|
||||
<string name="module_sort_action_first">並べ替え (アクション優先)</string>
|
||||
<string name="module_sort_enabled_first">並べ替え (最初に有効)</string>
|
||||
<string name="uninstall">アンインストール</string>
|
||||
<string name="restore">復元</string>
|
||||
<string name="module_install">インストール</string>
|
||||
<string name="install">インストール</string>
|
||||
<string name="reboot">再起動</string>
|
||||
<string name="settings">設定</string>
|
||||
<string name="reboot_userspace">通常の再起動</string>
|
||||
<string name="reboot_userspace">ソフトリブート</string>
|
||||
<string name="reboot_recovery">リカバリーへ再起動</string>
|
||||
<string name="reboot_bootloader">ブートローダーへ再起動</string>
|
||||
<string name="reboot_download">ダウンロードモードへ再起動</string>
|
||||
@@ -37,21 +43,21 @@
|
||||
<string name="module_uninstall_success">%s はアンインストールされました</string>
|
||||
<string name="module_uninstall_failed">%s をアンインストールできませんでした</string>
|
||||
<string name="module_version">バージョン</string>
|
||||
<string name="module_author">制作者</string>
|
||||
<string name="module_author">作者</string>
|
||||
<string name="refresh">更新</string>
|
||||
<string name="show_system_apps">システムアプリを表示</string>
|
||||
<string name="hide_system_apps">システムアプリを非表示</string>
|
||||
<string name="send_log">ログを送信</string>
|
||||
<string name="safe_mode">セーフモード</string>
|
||||
<string name="reboot_to_apply">再起動すると有効化されます</string>
|
||||
<string name="module_magisk_conflict">モジュールが Magisk との競合により利用できません!</string>
|
||||
<string name="home_learn_kernelsu">KernelSU について</string>
|
||||
<string name="module_magisk_conflict">モジュールが Magisk との競合により利用できません!</string>
|
||||
<string name="home_learn_kernelsu">KernelSU について学ぶ</string>
|
||||
<string name="home_learn_kernelsu_url">https://kernelsu.org/ja_JP/guide/what-is-kernelsu.html</string>
|
||||
<string name="home_click_to_learn_kernelsu">KernelSU のインストール方法やモジュールの使い方はこちら</string>
|
||||
<string name="home_click_to_learn_kernelsu">KernelSU のインストール方法やモジュールの使い方を学習できます</string>
|
||||
<string name="home_support_title">支援する</string>
|
||||
<string name="home_support_content">KernelSU はこれからもずっと無料でオープンソースです。寄付をして頂くことで、開発を支援していただけます。</string>
|
||||
<string name="profile">アプリのプロファイル</string>
|
||||
<string name="profile_default">既定</string>
|
||||
<string name="home_support_content">KernelSU は今後も無料でオープンソースです。ですが、寄付をして頂けると開発者への貢献になります。</string>
|
||||
<string name="about_source_code"><![CDATA[ソースコードは %1$s で確認できます。<br/>%2$s チャンネルにご参加ください。]]></string>
|
||||
<string name="profile_default">デフォルト</string>
|
||||
<string name="profile_template">テンプレート</string>
|
||||
<string name="profile_custom">カスタム</string>
|
||||
<string name="profile_name">プロファイル名</string>
|
||||
@@ -59,76 +65,201 @@
|
||||
<string name="profile_namespace_inherited">継承</string>
|
||||
<string name="profile_namespace_global">共通</string>
|
||||
<string name="profile_namespace_individual">分離</string>
|
||||
<string name="profile_umount_modules">モジュールのアンマウント</string>
|
||||
<string name="profile_groups">グループ</string>
|
||||
<string name="profile_capabilities">ケーパビリティ</string>
|
||||
<string name="profile_selinux_context">SELinux コンテキスト</string>
|
||||
<string name="profile_umount_modules">モジュールのアンマウント</string>
|
||||
<string name="failed_to_update_app_profile">%s のアプリのプロファイルの更新をできませでした</string>
|
||||
<string name="require_kernel_version" formatted="false">現在の KernelSU のバージョン %d は低すぎるため、マネージャーは正常に動作しません。バージョン %d 以上に更新してください!</string>
|
||||
<string name="settings_umount_modules_default">デフォルトでモジュールのマウントを解除</string>
|
||||
<string name="settings_umount_modules_default_summary">アプリプロファイルの「モジュールのアンマウント」の共通のデフォルト値です。 有効にすると、プロファイルセットを持たないアプリのシステムに対するすべてのモジュールの変更が削除されます。</string>
|
||||
<string name="settings_susfs_toggle">Kprobe フックを非表示にする</string>
|
||||
<string name="settings_susfs_toggle_summary">KSU によって生成された Kprobe フックを無効化して、代替となる組み込みの非 Kprobe を有効化します。Kprobe をサポートしない 非 GKI カーネルに適用される同等の機能を実装します。</string>
|
||||
<string name="profile_umount_modules_summary">このオプションを有効にすると、KernelSU はこのアプリのモジュールによって変更されたファイルを復元できるようになります。</string>
|
||||
<string name="profile_selinux_domain">ドメイン</string>
|
||||
<string name="profile_selinux_rules">ルール</string>
|
||||
<string name="new_version_available">新しいバージョン %s が利用可能です。タップしてダウンロード。</string>
|
||||
<string name="module_update">アップデート</string>
|
||||
<string name="module_update">更新</string>
|
||||
<string name="module_downloading">モジュールをダウンロード中: %s</string>
|
||||
<string name="module_start_downloading">ダウンロードを開始: %s</string>
|
||||
<string name="new_version_available">新しいバージョン %s が利用可能です。タップしてダウンロード。</string>
|
||||
<string name="launch_app">起動</string>
|
||||
<string name="force_stop_app" formatted="false">強制停止</string>
|
||||
<string name="restart_app">再起動</string>
|
||||
<string name="failed_to_update_sepolicy">SELinux ルールの更新に失敗しました %s</string>
|
||||
<string name="profile_capabilities">ケーパビリティ</string>
|
||||
<string name="module_downloading">モジュールをダウンロード中: %s</string>
|
||||
<string name="profile_umount_modules_summary">このオプションを有効にすると、KernelSU はこのアプリのモジュールによって変更されたファイルを復元できるようになります。</string>
|
||||
<string name="settings_umount_modules_default">既定でモジュールのマウントを解除</string>
|
||||
<string name="settings_umount_modules_default_summary">アプリプロファイルの「モジュールのアンマウント」の共通のデフォルト値です。 有効にすると、プロファイルセットを持たないアプリのシステムに対するすべてのモジュールの変更が削除されます。</string>
|
||||
<string name="module_changelog">変更履歴</string>
|
||||
<string name="app_profile_template_import_success">インポート成功</string>
|
||||
<string name="app_profile_export_to_clipboard">クリップボードからエクスポート</string>
|
||||
<string name="app_profile_template_export_empty">エクスポートするローカル テンプレートが見つかりません!</string>
|
||||
<string name="app_profile_template_id_exist">テンプレート ID はすでに存在します!</string>
|
||||
<string name="app_profile_import_from_clipboard">クリップボードからインポート</string>
|
||||
<string name="module_changelog_failed">変更ログの取得に失敗しました: %s</string>
|
||||
<string name="app_profile_template_name">名前</string>
|
||||
<string name="app_profile_template_id_invalid">無効なテンプレート ID</string>
|
||||
<string name="app_profile_template_sync">オンラインテンプレートの同期</string>
|
||||
<string name="settings_profile_template">アプリプロファイルのテンプレート</string>
|
||||
<string name="settings_profile_template_summary">アプリプロファイルのローカルおよびオンラインテンプレートを管理する</string>
|
||||
<string name="app_profile_template_create">テンプレートの作成</string>
|
||||
<string name="app_profile_template_readonly">読み取り専用</string>
|
||||
<string name="app_profile_import_export">インポート/エクスポート</string>
|
||||
<string name="app_profile_template_save_failed">テンプレートの保存に失敗しました</string>
|
||||
<string name="app_profile_template_edit">テンプレートの編集</string>
|
||||
<string name="app_profile_template_id">ID</string>
|
||||
<string name="settings_profile_template">アプリプロファイルのテンプレート</string>
|
||||
<string name="app_profile_template_id_invalid">無効なテンプレート ID</string>
|
||||
<string name="app_profile_template_name">名前</string>
|
||||
<string name="app_profile_template_description">説明</string>
|
||||
<string name="app_profile_template_save">保存</string>
|
||||
<string name="settings_profile_template_summary">アプリプロファイルのローカルおよびオンラインテンプレートを管理する</string>
|
||||
<string name="app_profile_template_delete">消去</string>
|
||||
<string name="app_profile_template_import_empty">クリップボードが空です!</string>
|
||||
<string name="app_profile_template_view">テンプレートを表示</string>
|
||||
<string name="settings_check_update">アップデートを確認</string>
|
||||
<string name="settings_check_update_summary">アプリを開いたときにアップデートを自動的に確認する</string>
|
||||
<string name="app_profile_template_readonly">読み取り専用</string>
|
||||
<string name="app_profile_template_id_exist">テンプレート ID はすでに存在します!</string>
|
||||
<string name="app_profile_import_export">インポートとエクスポート</string>
|
||||
<string name="app_profile_import_from_clipboard">クリップボードからインポート</string>
|
||||
<string name="app_profile_export_to_clipboard">クリップボードからエクスポート</string>
|
||||
<string name="app_profile_template_export_empty">エクスポートするローカル テンプレートが見つかりません!</string>
|
||||
<string name="app_profile_template_import_success">インポートが成功しました</string>
|
||||
<string name="app_profile_template_sync">オンラインテンプレートの同期</string>
|
||||
<string name="app_profile_template_save_failed">テンプレートの保存に失敗しました</string>
|
||||
<string name="app_profile_template_import_empty">クリップボードが空です!</string>
|
||||
<string name="module_changelog_failed">変更ログの取得に失敗しました: %s</string>
|
||||
<string name="settings_check_update">更新を確認</string>
|
||||
<string name="settings_check_update_summary">アプリを開いたときに更新を自動的に確認します</string>
|
||||
<string name="grant_root_failed">root の付与に失敗しました!</string>
|
||||
<string name="action">アクション</string>
|
||||
<string name="open">開く</string>
|
||||
<string name="enable_web_debugging">WebView デバッグを有効にする</string>
|
||||
<string name="enable_web_debugging">WebView デバッグを有効化する</string>
|
||||
<string name="enable_web_debugging_summary">WebUI のデバッグに使用できます。必要な場合にのみ有効にしてください。</string>
|
||||
<string name="select_file_tip">%1$s パーティション イメージが推奨されます</string>
|
||||
<string name="select_kmi">KMI を選択してください</string>
|
||||
<string name="install_next">次に</string>
|
||||
<string name="direct_install">直接インストール (推奨)</string>
|
||||
<string name="select_file">ファイルを選択してください</string>
|
||||
<string name="install_inactive_slot">非アクティブなスロットにインストール (OTA 後)</string>
|
||||
<string name="install_inactive_slot_warning">再起動後、デバイスは**強制的に**、現在非アクティブなスロットから起動します。
|
||||
\nこのオプションは、OTA が完了した後にのみ使用してください。
|
||||
\n続く?</string>
|
||||
<string name="direct_install">直接インストール (推奨)</string>
|
||||
<string name="select_file">ファイルを選択してください</string>
|
||||
\n続行しますか?</string>
|
||||
<string name="install_next">次へ</string>
|
||||
<string name="select_file_tip">%1$s のパーティションイメージを推奨します</string>
|
||||
<string name="select_kmi">KMI を選択してください</string>
|
||||
<string name="settings_uninstall">アンインストール</string>
|
||||
<string name="settings_uninstall_temporary">一時的にアンインストールする</string>
|
||||
<string name="settings_uninstall_permanent">完全にアンインストールする</string>
|
||||
<string name="settings_restore_stock_image">ストックイメージを復元</string>
|
||||
<string name="settings_uninstall_temporary">一時的にアンインストールする</string>
|
||||
<string name="settings_uninstall">アンインストール</string>
|
||||
<string name="settings_uninstall_temporary_message">KernelSU を一時的にアンインストールし、次回の再起動後に元の状態に戻します。</string>
|
||||
<string name="settings_uninstall_permanent_message">KernelSU (ルートおよびすべてのモジュール) を完全かつ永久にアンインストールします。</string>
|
||||
<string name="settings_uninstall_permanent_message">KernelSU (root およびすべてのモジュール) を完全かつ恒久的にアンインストールします。</string>
|
||||
<string name="settings_restore_stock_image_message">バックアップが存在する場合、工場出荷時のイメージを復元できます (OTA の前に使用してください)。KernelSU をアンインストールする必要がある場合は、「完全にアンインストールする」を使用してください。</string>
|
||||
<string name="flashing">フラッシュ</string>
|
||||
<string name="flash_success">フラッシュ成功</string>
|
||||
<string name="flash_failed">フラッシュ失敗</string>
|
||||
<string name="flash_success">フラッシュが成功しました</string>
|
||||
<string name="flash_failed">フラッシュに失敗しました</string>
|
||||
<string name="selected_lkm">選択された LKM: %s</string>
|
||||
<string name="save_log">ログを保存</string>
|
||||
<string name="action">アクション</string>
|
||||
<string name="log_saved">保存されたログ</string>
|
||||
<string name="module_sort_enabled_first">並べ替え(最初に有効)</string>
|
||||
<string name="module_sort_action_first">並べ替え(アクション優先)</string>
|
||||
<string name="status_supported">対応</string>
|
||||
<string name="status_not_supported">非対応</string>
|
||||
<string name="status_unknown">不明</string>
|
||||
<string name="sus_su_mode">SuS SU モード:</string>
|
||||
<!-- Module related -->
|
||||
<string name="module_install_confirm">%1$s のモジュールをインストールしますか?</string>
|
||||
<string name="unknown_module">不明なモジュール</string>
|
||||
<!-- Restore related -->
|
||||
<string name="restore_confirm_title">モジュールの復元を確認</string>
|
||||
<string name="restore_confirm_message">この操作によりモジュールが上書きされます。続行しますか?</string>
|
||||
<string name="confirm">確認</string>
|
||||
<string name="cancel">キャンセル</string>
|
||||
<!-- Backup related -->
|
||||
<string name="backup_success">バックアップが完了しました (tar.gz)</string>
|
||||
<string name="backup_failed">バックアップに失敗: %1$s</string>
|
||||
<string name="backup_modules">モジュールをバックアップ</string>
|
||||
<string name="restore_modules">モジュールを復元</string>
|
||||
<!-- Restore related messages -->
|
||||
<string name="restore_success">モジュールは正常に復元されました、再起動が必要です</string>
|
||||
<string name="restore_failed">復元に失敗: %1$s</string>
|
||||
<string name="restart_now">今すぐ再起動</string>
|
||||
<string name="unknown_error">不明なエラー</string>
|
||||
<!-- Command related -->
|
||||
<string name="command_execution_failed">コマンドの実行に失敗しました: %1$s</string>
|
||||
<!-- Allowlist related -->
|
||||
<string name="allowlist_backup_success">許可リストのバックアップが成功しました</string>
|
||||
<string name="allowlist_backup_failed">許可リストのバックアップに失敗: %1$s</string>
|
||||
<string name="allowlist_restore_confirm_title">許可リストの復元を確認</string>
|
||||
<string name="allowlist_restore_confirm_message">この操作により許可リストが上書きされます。続行しますか?</string>
|
||||
<string name="allowlist_restore_success">許可リストの復元が成功しました</string>
|
||||
<string name="allowlist_restore_failed">許可リストの復元に失敗: %1$s</string>
|
||||
<string name="backup_allowlist">許可リストをバックアップ</string>
|
||||
<string name="restore_allowlist">許可リストを復元</string>
|
||||
<string name="settings_custom_background">カスタム背景を設定</string>
|
||||
<string name="settings_custom_background_summary">カスタム背景を設定します</string>
|
||||
<string name="settings_card_manage">カードの管理</string>
|
||||
<string name="settings_card_alpha">カードのアルファ</string>
|
||||
<string name="settings_restore_default">デフォルトに復元</string>
|
||||
<string name="home_android_version">Android のバージョン</string>
|
||||
<string name="home_device_model">デバイスモデル</string>
|
||||
<string name="su_not_allowed">%s にスーパーユーザー権限を付与することはできません</string>
|
||||
<string name="settings_disable_su">su の互換性を無効化する</string>
|
||||
<string name="settings_disable_su_summary">su コマンドを使用してアプリが root 権限を取得する動作を一時的に無効化します (既存の root プロセスは影響を受けません)。</string>
|
||||
<string name="using_mksu_manager">SukiSU Beta Manager を使用中です</string>
|
||||
<string name="module_install_multiple_confirm">選択した %d 個のモジュールをインストールしてもよろしいですか?</string>
|
||||
<string name="module_install_multiple_confirm_with_names">%1$d 個のモジュールをインストールしてもよろしいですか?\n\n%2$s</string>
|
||||
<string name="more_settings">その他の設定</string>
|
||||
<string name="selinux">SELinux</string>
|
||||
<string name="selinux_enabled">有効</string>
|
||||
<string name="selinux_disabled">無効</string>
|
||||
<string name="simple_mode">シンプルモード</string>
|
||||
<string name="simple_mode_summary">ON にすると不要なカードを隠します</string>
|
||||
<string name="hide_kernel_kernelsu_version">カーネルのバージョンを非表示にする</string>
|
||||
<string name="hide_kernel_kernelsu_version_summary">カーネルのバージョンを非表示にします</string>
|
||||
<string name="hide_other_info">その他の情報を非表示にする</string>
|
||||
<string name="hide_other_info_summary">ホームページ上のスーパーユーザー、モジュール、KPM モジュールの数に関する情報を隠します。</string>
|
||||
<string name="hide_susfs_status">SuSFS ステータスを非表示にする</string>
|
||||
<string name="hide_susfs_status_summary">ホームページ上の SuSFS ステータス情報を隠します</string>
|
||||
<string name="theme_mode">テーマモード</string>
|
||||
<string name="theme_follow_system">システムに従う</string>
|
||||
<string name="theme_light">ライトカラー</string>
|
||||
<string name="theme_dark">ダークカラー</string>
|
||||
<string name="manual_hook">手動でフック</string>
|
||||
<string name="dynamic_color_title">ダイナミックカラー</string>
|
||||
<string name="dynamic_color_summary">システムテーマのダイナミックカラーを使用します</string>
|
||||
<string name="choose_theme_color">テーマカラーを選択</string>
|
||||
<string name="color_default">ホワイト</string>
|
||||
<string name="color_blue">ブルー</string>
|
||||
<string name="color_green">グリーン</string>
|
||||
<string name="color_purple">パープル</string>
|
||||
<string name="color_orange">オレンジ</string>
|
||||
<string name="color_pink">ピンク</string>
|
||||
<string name="color_gray">グレー</string>
|
||||
<string name="color_ivory">アイボリー</string>
|
||||
<string name="flash_option">ブラシの設定</string>
|
||||
<string name="flash_option_tip">フラッシュするファイルを選択</string>
|
||||
<string name="horizon_kernel">AnyKernel3 をフラッシュ</string>
|
||||
<string name="root_required">root 権限が必要です</string>
|
||||
<string name="copy_failed">ファイルのコピーに失敗しました</string>
|
||||
<string name="reboot_complete_title">スクラブが完了しました</string>
|
||||
<string name="reboot_complete_msg">すぐに再起動しますか?</string>
|
||||
<string name="yes">はい</string>
|
||||
<string name="no">いいえ</string>
|
||||
<string name="failed_reboot">再起動に失敗しました</string>
|
||||
<string name="batch_authorization">bulk ライセンス</string>
|
||||
<string name="batch_cancel_authorization">認証を一括でキャンセル</string>
|
||||
<string name="backup">バックアップ</string>
|
||||
<string name="color_yellow">イエロー</string>
|
||||
<string name="kpm">KPM モジュール</string>
|
||||
<string name="kpm_title">カーネルモジュール</string>
|
||||
<string name="kpm_empty">カーネルモジュールは現在インストールされていません</string>
|
||||
<string name="kpm_version">リリース</string>
|
||||
<string name="kpm_author">作者</string>
|
||||
<string name="kpm_uninstall">アンインストール</string>
|
||||
<string name="kpm_uninstall_success">アンインストールに失敗しました</string>
|
||||
<string name="kpm_uninstall_failed">アンインストールに失敗しました</string>
|
||||
<string name="kpm_install">インストールを選択</string>
|
||||
<string name="kpm_install_success">KPM モジュールの読み込みに成功しました</string>
|
||||
<string name="kpm_install_failed">KPM モジュールの読み込みに失敗しました</string>
|
||||
<string name="kpm_args">KPM パラメーター</string>
|
||||
<string name="kpm_control">完全</string>
|
||||
<string name="home_kpm_version">KPM のバージョン</string>
|
||||
<string name="close_notice">閉じる</string>
|
||||
<string name="kernel_module_notice">以下のカーネルモジュール関数は KernelPatch によって開発され、SukiSU Ultra のカーネルモジュール関数を含むように変更されました</string>
|
||||
<string name="home_ContributionCard_kernelsu">SukiSU Ultra の今後にご期待ください</string>
|
||||
<string name="kpm_control_success">成功</string>
|
||||
<string name="kpm_control_failed">失敗</string>
|
||||
<string name="home_click_to_ContributionCard_kernelsu">SukiSU Ultra は将来的に KSU から比較的に独立したブランチになりますが、公式の KernelSU や MKSU などの貢献に繋がるでしょう!</string>
|
||||
<string name="not_supported">非対応</string>
|
||||
<string name="supported">対応</string>
|
||||
<string name="home_kpm_module">KPM モジュール数:%d </string>
|
||||
<string name="kpm_invalid_file">無効な KPM ファイル</string>
|
||||
<string name="kernel_patched">カーネルはパッチされていません</string>
|
||||
<string name="kernel_not_enabled">カーネルは設定されていません</string>
|
||||
<string name="custom_settings">カスタム設定</string>
|
||||
<string name="kpm_install_mode">インストール</string>
|
||||
<string name="kpm_install_mode_load">読み込む</string>
|
||||
<string name="kpm_install_mode_embed">埋め込む</string>
|
||||
<string name="kpm_install_mode_description">モジュールのインストールモードを選択してください:\n\n読み込む: モジュールを一時的に読み込みます\n埋め込む: システムに恒久的にインストールします</string>
|
||||
<string name="log_failed_to_check_module_file">モジュールファイルの存在を確認できませんでした</string>
|
||||
<string name="snackbar_failed_to_check_module_file">モジュールファイルが存在するか確認できません</string>
|
||||
<string name="confirm_uninstall_title">アンインストールを確認</string>
|
||||
<string name="confirm_uninstall_confirm">アンインストール中</string>
|
||||
<string name="confirm_uninstall_dismiss">中止</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,2 +1,265 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources></resources>
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">SukiSU Ultra</string>
|
||||
<string name="home">Home</string>
|
||||
<string name="home_not_installed">Chưa cài đặt</string>
|
||||
<string name="home_click_to_install">Nhấn để cài đặt</string>
|
||||
<string name="home_working">Đang làm việc</string>
|
||||
<string name="home_working_version">Phiên bản: %d</string>
|
||||
<string name="home_superuser_count">Superusers: %d</string>
|
||||
<string name="home_module_count">Mô-đun: %d</string>
|
||||
<string name="home_unsupported">Không được hỗ trợ</string>
|
||||
<string name="home_unsupported_reason">Không phát hiện được trình điều khiển KernelSU trên kernel của bạn.</string>
|
||||
<string name="home_kernel">Kernel</string>
|
||||
<string name="home_susfs">SuSFS: %s</string>
|
||||
<string name="home_susfs_version">Phiên bản SuSFS</string>
|
||||
<string name="home_susfs_sus_su">SuS SU</string>
|
||||
<string name="home_manager_version">Phiên bản quản lý</string>
|
||||
<string name="home_fingerprint">Dấu vân tay</string>
|
||||
<string name="home_selinux_status">Trạng thái SELinux</string>
|
||||
<string name="selinux_status_disabled">Disabled</string>
|
||||
<string name="selinux_status_enforcing">Enforcing</string>
|
||||
<string name="selinux_status_permissive">Permissive</string>
|
||||
<string name="selinux_status_unknown">Không rõ</string>
|
||||
<string name="superuser">Superuser</string>
|
||||
<string name="module_failed_to_enable">Không thể bật mô-đun: %s</string>
|
||||
<string name="module_failed_to_disable">Không thể vô hiệu hóa mô-đun: %s</string>
|
||||
<string name="module_empty">Không có mô-đun nào được cài đặt</string>
|
||||
<string name="module">Mô-đun</string>
|
||||
<string name="module_sort_action_first">Sắp xếp (theo hành động)</string>
|
||||
<string name="module_sort_enabled_first">Sắp xếp (theo trạng thái)</string>
|
||||
<string name="uninstall">Gỡ cài đặt</string>
|
||||
<string name="restore">Khôi phục</string>
|
||||
<string name="module_install">Cài đặt</string>
|
||||
<string name="install">Cài đặt</string>
|
||||
<string name="reboot">Khởi động lại</string>
|
||||
<string name="settings">Cài đặt</string>
|
||||
<string name="reboot_userspace">Khởi động lại không gian người dùng</string>
|
||||
<string name="reboot_recovery">Khởi động lại vào Recovery</string>
|
||||
<string name="reboot_bootloader">Khởi động lại vào Bootloader</string>
|
||||
<string name="reboot_download">Khởi động lại vào Download mode</string>
|
||||
<string name="reboot_edl">Khởi động lại vào EDL</string>
|
||||
<string name="about">Thông tin</string>
|
||||
<string name="module_uninstall_confirm">Bạn có chắc chắn muốn gỡ cài đặt mô-đun %s không?</string>
|
||||
<string name="module_uninstall_success">%s đã gỡ cài đặt</string>
|
||||
<string name="module_uninstall_failed">Không thể gỡ cài đặt: %s</string>
|
||||
<string name="module_version">Phiên bản</string>
|
||||
<string name="module_author">Tác giả</string>
|
||||
<string name="refresh">Làm mới</string>
|
||||
<string name="show_system_apps">Hiển thị ứng dụng hệ thống</string>
|
||||
<string name="hide_system_apps">Ẩn ứng dụng hệ thống</string>
|
||||
<string name="send_log">Gửi nhật ký</string>
|
||||
<string name="safe_mode">Chế độ an toàn</string>
|
||||
<string name="reboot_to_apply">Khởi động lại để có hiệu lực</string>
|
||||
<string name="module_magisk_conflict">Các mô-đun không khả dụng do xung đột với Magisk!</string>
|
||||
<string name="home_learn_kernelsu">Tìm hiểu KernelSU</string>
|
||||
<string name="home_learn_kernelsu_url">https://kernelsu.org/guide/what-is-kernelsu.html</string>
|
||||
<string name="home_click_to_learn_kernelsu">Tìm hiểu cách cài đặt KernelSU và sử dụng các mô-đun</string>
|
||||
<string name="home_support_title">Hỗ trợ chúng tôi</string>
|
||||
<string name="home_support_content">KernelSU sẽ luôn là miễn phí và mã nguồn mở. Tuy nhiên, bạn có thể cho chúng tôi thấy rằng bạn quan tâm bằng cách quyên góp.</string>
|
||||
<string name="about_source_code"><![CDATA[View source code at %1$s<br/>Tham gia kênh %2$s của chúng tôi]]></string>
|
||||
<string name="profile" translatable="false">Hồ sơ ứng dụng</string>
|
||||
<string name="profile_default">Mặc định</string>
|
||||
<string name="profile_template">Bản mẫu</string>
|
||||
<string name="profile_custom">Tùy chỉnh</string>
|
||||
<string name="profile_name">Tên hồ sơ</string>
|
||||
<string name="profile_namespace">Tên không gian gắn kết</string>
|
||||
<string name="profile_namespace_inherited">Được thừa hưởng</string>
|
||||
<string name="profile_namespace_global">Toàn cầu</string>
|
||||
<string name="profile_namespace_individual">Cá nhân</string>
|
||||
<string name="profile_groups">Nhóm</string>
|
||||
<string name="profile_capabilities">Khả năng</string>
|
||||
<string name="profile_selinux_context">Bối cảnh SELinux</string>
|
||||
<string name="profile_umount_modules">Bỏ gắn kết mô-đun</string>
|
||||
<string name="failed_to_update_app_profile">Không cập nhật được Hồ sơ ứng dụng cho %s</string>
|
||||
<string name="require_kernel_version" formatted="false">Phiên bản KernelSU hiện tại %d quá thấp để trình quản lý hoạt động bình thường. Vui lòng nâng cấp lên phiên bản %d hoặc cao hơn!</string>
|
||||
<string name="settings_umount_modules_default">Bỏ gắn kết các mô-đun theo mặc định</string>
|
||||
<string name="settings_umount_modules_default_summary">Giá trị mặc định cho \"Bỏ gắn kết các mô-đun\" trong Hồ sơ ứng dụng. Nếu được bật, nó sẽ xóa tất cả các sửa đổi của mô-đun đối với hệ thống đối và các ứng dụng không có hồ sơ được đặt.</string>
|
||||
<string name="settings_susfs_toggle">Ẩn móc kprobe</string>
|
||||
<string name="settings_susfs_toggle_summary">Vô hiệu hóa các móc kprobe do KSU tạo ra và kích hoạt các móc không phải kprobe tích hợp sẵn, triển khai sẽ được áp dụng cho hạt nhân không phải GKI, không hỗ trợ krp</string>
|
||||
<string name="profile_umount_modules_summary">Bật tùy chọn này sẽ cho phép KernelSU khôi phục mọi tệp đã được các mô-đun sửa đổi cho ứng dụng này.</string>
|
||||
<string name="profile_selinux_domain">Domain</string>
|
||||
<string name="profile_selinux_rules">Quy tắc</string>
|
||||
<string name="module_update">Cập nhật</string>
|
||||
<string name="module_downloading">Đang tải xuống mô-đun: %s</string>
|
||||
<string name="module_start_downloading">Bắt đầu tải xuống: %s</string>
|
||||
<string name="new_version_available">Phiên bản mới %s đã có sẵn, hãy nhấp để cập nhật.</string>
|
||||
<string name="launch_app">Khởi chạy</string>
|
||||
<string name="force_stop_app" formatted="false">Buộc dừng</string>
|
||||
<string name="restart_app">Khởi động lại</string>
|
||||
<string name="failed_to_update_sepolicy">Không cập nhật được quy tắc SELinux cho %s</string>
|
||||
<string name="module_changelog">Nhật ký thay đổi</string>
|
||||
<string name="settings_profile_template">Mẫu hồ sơ ứng dụng</string>
|
||||
<string name="settings_profile_template_summary">Quản lý mẫu cục bộ và trực tuyến của Hồ sơ ứng dụng</string>
|
||||
<string name="app_profile_template_create">Tạo mẫu</string>
|
||||
<string name="app_profile_template_edit">Chỉnh sửa mẫu</string>
|
||||
<string name="app_profile_template_id">ID</string>
|
||||
<string name="app_profile_template_id_invalid">ID mẫu không hợp lệ</string>
|
||||
<string name="app_profile_template_name">Tên</string>
|
||||
<string name="app_profile_template_description">Miêu tả</string>
|
||||
<string name="app_profile_template_save">Lưu</string>
|
||||
<string name="app_profile_template_delete">Xoá</string>
|
||||
<string name="app_profile_template_view">Xem mẫu</string>
|
||||
<string name="app_profile_template_readonly">Chỉ đọc</string>
|
||||
<string name="app_profile_template_id_exist">ID mẫu đã tồn tại!</string>
|
||||
<string name="app_profile_import_export">Nhập/Xuất</string>
|
||||
<string name="app_profile_import_from_clipboard">Nhập từ bộ nhớ tạm clipboard</string>
|
||||
<string name="app_profile_export_to_clipboard">Xuất vào bộ nhớ tạm clipboard</string>
|
||||
<string name="app_profile_template_export_empty">Cannot find local template to export!</string>
|
||||
<string name="app_profile_template_import_success">Đã nhập thành công</string>
|
||||
<string name="app_profile_template_sync">Đồng bộ mẫu trực tuyến</string>
|
||||
<string name="app_profile_template_save_failed">Không lưu được mẫu</string>
|
||||
<string name="app_profile_template_import_empty">Bộ nhớ tạm đang trống!</string>
|
||||
<string name="module_changelog_failed">Lấy nhật ký thay đổi không thành công: %s</string>
|
||||
<string name="settings_check_update">Kiểm tra cập nhật</string>
|
||||
<string name="settings_check_update_summary">Tự động kiểm tra cập nhật khi mở ứng dụng</string>
|
||||
<string name="grant_root_failed">Không cấp được quyền root!</string>
|
||||
<string name="action">Khởi chạy</string>
|
||||
<string name="open">Mở</string>
|
||||
<string name="enable_web_debugging">Bật gỡ lỗi WebView</string>
|
||||
<string name="enable_web_debugging_summary">Có thể sử dụng để gỡ lỗi WebUI. Vui lòng chỉ bật khi cần thiết.</string>
|
||||
<string name="direct_install">Cài đặt trực tiếp (Khuyến nghị)</string>
|
||||
<string name="select_file">Chọn một tập tin</string>
|
||||
<string name="install_inactive_slot">Cài đặt vào khe không hoạt động (Sau OTA)</string>
|
||||
<string name="install_inactive_slot_warning">Thiết bị của bạn sẽ **BUỘC** phải khởi động vào khe cắm hiện tại không hoạt động sau khi khởi động lại!\nChỉ sử dụng tùy chọn này sau khi OTA hoàn tất.\nTiếp tục?</string>
|
||||
<string name="install_next">Kế tiếp</string>
|
||||
<string name="select_file_tip">Phân vùng %1$s được khuyến nghị</string>
|
||||
<string name="select_kmi">Chọn KMI</string>
|
||||
<string name="settings_uninstall">Uninstall</string>
|
||||
<string name="settings_uninstall_temporary">Gỡ cài đặt tạm thời</string>
|
||||
<string name="settings_uninstall_permanent">Gỡ cài đặt vĩnh viễn</string>
|
||||
<string name="settings_restore_stock_image">Khôi phục img ban đầu</string>
|
||||
<string name="settings_uninstall_temporary_message">Gỡ cài đặt tạm thời KernelSU, khôi phục lại trạng thái ban đầu sau lần khởi động lại tiếp theo.</string>
|
||||
<string name="settings_uninstall_permanent_message">Gỡ cài đặt KernelSU (Root và tất cả các mô-đun) hoàn toàn và vĩnh viễn.</string>
|
||||
<string name="settings_restore_stock_image_message">Khôi phục ảnh gốc (nếu có bản sao lưu), thường được sử dụng trước OTA; nếu bạn cần gỡ cài đặt KernelSU, vui lòng sử dụng \"Gỡ cài đặt vĩnh viễn\".</string>
|
||||
<string name="flashing">Đang flash...</string>
|
||||
<string name="flash_success">Flash thành công</string>
|
||||
<string name="flash_failed">Lỗi flash</string>
|
||||
<string name="selected_lkm">LKM đã chọn: %s</string>
|
||||
<string name="save_log">Lưu nhật ký</string>
|
||||
<string name="log_saved">Nhật ký đã lưu</string>
|
||||
<string name="status_supported">Được hỗ trợ</string>
|
||||
<string name="status_not_supported">Không được hỗ trợ</string>
|
||||
<string name="status_unknown">Không rõ</string>
|
||||
<string name="sus_su_mode">Chế độ SuS: SU</string>
|
||||
<!-- Module related -->
|
||||
<string name="module_install_confirm">Xác nhận cài đặt mô-đun %1$s ?</string>
|
||||
<string name="unknown_module">Mô-đun không xác định</string>
|
||||
<!-- Restore related -->
|
||||
<string name="restore_confirm_title">Xác nhận khôi phục mô-đun</string>
|
||||
<string name="restore_confirm_message">Hành động này sẽ ghi đè lên tất cả các mô-đun hiện có. Tiếp tục?</string>
|
||||
<string name="confirm">Xác nhận</string>
|
||||
<string name="cancel">Hủy bỏ</string>
|
||||
<!-- Backup related -->
|
||||
<string name="backup_success">Sao lưu thành công (tar.gz)</string>
|
||||
<string name="backup_failed">Sao lưu không thành công: %1$s</string>
|
||||
<string name="backup_modules">Sao lưu mô-đun</string>
|
||||
<string name="restore_modules">Khôi phục các mô-đun</string>
|
||||
<!-- Restore related messages -->
|
||||
<string name="restore_success">Các mô-đun đã được khôi phục thành công, cần khởi động lại</string>
|
||||
<string name="restore_failed">Khôi phục không thành công: %1$s</string>
|
||||
<string name="restart_now">Khởi động lại ngay</string>
|
||||
<string name="unknown_error">Lỗi không xác định</string>
|
||||
<!-- Command related -->
|
||||
<string name="command_execution_failed">Thực hiện lệnh không thành công: %1$s</string>
|
||||
<!-- Allowlist related -->
|
||||
<string name="allowlist_backup_success">Sao lưu danh sách cho phép thành công</string>
|
||||
<string name="allowlist_backup_failed">Sao lưu danh sách cho phép không thành công: %1$s</string>
|
||||
<string name="allowlist_restore_confirm_title">Xác nhận khôi phục danh sách cho phép</string>
|
||||
<string name="allowlist_restore_confirm_message">Hành động này sẽ ghi đè lên danh sách cho phép hiện tại. Tiếp tục?</string>
|
||||
<string name="allowlist_restore_success">Đã khôi phục danh sách cho phép thành công</string>
|
||||
<string name="allowlist_restore_failed">Khôi phục danh sách cho phép không thành công: %1$s</string>
|
||||
<string name="backup_allowlist">Sao lưu danh sách cho phép</string>
|
||||
<string name="restore_allowlist">Khôi phục danh sách cho phép</string>
|
||||
<string name="settings_custom_background">Cài đặt nền tùy chỉnh</string>
|
||||
<string name="settings_custom_background_summary">Cài đặt tùy chỉnh nền</string>
|
||||
<string name="settings_card_manage">Quản lý thẻ</string>
|
||||
<string name="settings_card_alpha">Thẻ alpha</string>
|
||||
<string name="settings_restore_default">Khôi phục mặc định</string>
|
||||
<string name="home_android_version">Phiên bản Android</string>
|
||||
<string name="home_device_model">Model thiết bị</string>
|
||||
<string name="su_not_allowed">Không được phép cấp siêu người dùng cho %s</string>
|
||||
<string name="settings_disable_su">Vô hiệu hóa khả năng tương thích su</string>
|
||||
<string name="settings_disable_su_summary">Tạm thời vô hiệu hóa mọi ứng dụng khỏi quyền root thông qua lệnh su (các tiến trình root hiện có sẽ không bị ảnh hưởng).</string>
|
||||
<string name="using_mksu_manager">Bạn đang sử dụng trình quản lý SukiSU thử nghiệm</string>
|
||||
<string name="module_install_multiple_confirm">Bạn có chắc chắn muốn cài đặt các mô-đun %d đã chọn không?</string>
|
||||
<string name="module_install_multiple_confirm_with_names">Bạn có chắc chắn muốn cài đặt các mô-đun %1$d sau không? \n\n%2$s</string>
|
||||
<string name="more_settings">Nhiều thiết lập hơn</string>
|
||||
<string name="selinux">SELinux</string>
|
||||
<string name="selinux_enabled">Đã bật</string>
|
||||
<string name="selinux_disabled">Đã tắt</string>
|
||||
<string name="simple_mode">Chế độ đơn giản</string>
|
||||
<string name="simple_mode_summary">Ẩn các thẻ không cần thiết khi bật</string>
|
||||
<string name="hide_kernel_kernelsu_version">Ẩn phiên bản kernel</string>
|
||||
<string name="hide_kernel_kernelsu_version_summary">Ẩn phiên bản kernel hiện tại</string>
|
||||
<string name="hide_other_info">Ẩn thông tin thêm</string>
|
||||
<string name="hide_other_info_summary">Ẩn thông tin về số lượng app đã được cấp root, mô-đun và mô-đun KPM trên trang chủ</string>
|
||||
<string name="hide_susfs_status">Ẩn trạng thái SuSFS</string>
|
||||
<string name="hide_susfs_status_summary">Ẩn thông tin trạng thái SuSFS trên trang chủ</string>
|
||||
<string name="theme_mode">Chế độ chủ đề</string>
|
||||
<string name="theme_follow_system">Theo hệ thống</string>
|
||||
<string name="theme_light">Sáng</string>
|
||||
<string name="theme_dark">Tối</string>
|
||||
<string name="manual_hook">Móc thủ công</string>
|
||||
<string name="dynamic_color_title">Màu sắc động</string>
|
||||
<string name="dynamic_color_summary">Màu sắc động sử dụng chủ đề hệ thống</string>
|
||||
<string name="choose_theme_color">Chọn màu chủ đề</string>
|
||||
<string name="color_default">Trắng</string>
|
||||
<string name="color_blue">Xanh dương</string>
|
||||
<string name="color_green">Xanh lá</string>
|
||||
<string name="color_purple">Tím</string>
|
||||
<string name="color_orange">Cam</string>
|
||||
<string name="color_pink">Hồng</string>
|
||||
<string name="color_gray">Xám</string>
|
||||
<string name="color_ivory">Ngà voi</string>
|
||||
<string name="flash_option">Tùy chọn cọ</string>
|
||||
<string name="flash_option_tip">Chọn tập tin cần flash</string>
|
||||
<string name="horizon_kernel">File Anykernel3</string>
|
||||
<string name="root_required">Yêu cầu quyền root</string>
|
||||
<string name="copy_failed">Sao chép tập tin không thành công</string>
|
||||
<string name="reboot_complete_title">Hoàn tất</string>
|
||||
<string name="reboot_complete_msg">khởi động lại ngay lập tức?</string>
|
||||
<string name="yes">Có</string>
|
||||
<string name="no">Không</string>
|
||||
<string name="failed_reboot">Khởi động lại không thành công</string>
|
||||
<string name="batch_authorization">Giấy phép số lượng lớn</string>
|
||||
<string name="batch_cancel_authorization">Hủy ủy quyền hàng loạt</string>
|
||||
<string name="backup">Sao lưu</string>
|
||||
<string name="color_yellow">Vàng</string>
|
||||
<string name="kpm">Mô-đun kpm</string>
|
||||
<string name="kpm_title">Mô-đun kernel</string>
|
||||
<string name="kpm_empty">Không có mô-đun kernel nào được cài đặt tại thời điểm này</string>
|
||||
<string name="kpm_version">Phát hành</string>
|
||||
<string name="kpm_author">Tác giả</string>
|
||||
<string name="kpm_uninstall">Gỡ cài đặt</string>
|
||||
<string name="kpm_uninstall_success">Đã gỡ cài đặt thành công</string>
|
||||
<string name="kpm_uninstall_failed">Không thể gỡ cài đặt</string>
|
||||
<string name="kpm_install">Chọn Cài đặt</string>
|
||||
<string name="kpm_install_success">Tải module kpm thành công</string>
|
||||
<string name="kpm_install_failed">Tải module kpm không thành công</string>
|
||||
<string name="kpm_args">thông số kpm</string>
|
||||
<string name="kpm_control">fulfillment</string>
|
||||
<string name="home_kpm_version">Phiên bản KPM</string>
|
||||
<string name="close_notice">đóng</string>
|
||||
<string name="kernel_module_notice">Các chức năng mô-đun kernel sau đây được KernelPatch phát triển và sửa đổi để bao gồm các chức năng mô-đun hạt nhân của SukiSU Ultra</string>
|
||||
<string name="home_ContributionCard_kernelsu">SukiSU Ultra Mong đợi</string>
|
||||
<string name="kpm_control_success">thành công</string>
|
||||
<string name="kpm_control_failed">thất bại</string>
|
||||
<string name="home_click_to_ContributionCard_kernelsu">SukiSU Ultra sẽ là một nhánh tương đối độc lập của KSU trong tương lai, nhưng xin cảm ơn KernelSU và MKSU chính thức vì những đóng góp của họ!</string>
|
||||
<string name="not_supported">không được hỗ trợ</string>
|
||||
<string name="supported">được hỗ trợ</string>
|
||||
<string name="home_kpm_module">Số lượng mô-đun KPM:%d </string>
|
||||
<string name="kpm_invalid_file">Tệp KPM không hợp lệ</string>
|
||||
<string name="kernel_patched">Kernel chưa được vá</string>
|
||||
<string name="kernel_not_enabled">Kernel chưa được cấu hình</string>
|
||||
<string name="custom_settings">Cài đặt tùy chỉnh</string>
|
||||
<string name="kpm_install_mode">cài đặt</string>
|
||||
<string name="kpm_install_mode_load">tải</string>
|
||||
<string name="kpm_install_mode_embed">nhúng</string>
|
||||
<string name="kpm_install_mode_description">Vui lòng chọn chế độ cài đặt mô-đun: \n\nTải: Tải tạm thời mô-đun \nNhúng: Cài đặt vĩnh viễn vào hệ thống</string>
|
||||
<string name="log_failed_to_check_module_file">Không kiểm tra được sự tồn tại của tệp mô-đun</string>
|
||||
<string name="snackbar_failed_to_check_module_file">Không thể kiểm tra xem tệp mô-đun có tồn tại không</string>
|
||||
<string name="confirm_uninstall_title">Xác nhận gỡ cài đặt</string>
|
||||
<string name="confirm_uninstall_confirm">loại bỏ</string>
|
||||
<string name="confirm_uninstall_dismiss">bãi bỏ</string>
|
||||
</resources>
|
||||
|
||||
@@ -230,11 +230,9 @@
|
||||
<string name="kpm_version">版本</string>
|
||||
<string name="kpm_author">作者</string>
|
||||
<string name="kpm_uninstall">卸载</string>
|
||||
<string name="kpm_uninstall_confirm">确定要卸载内核模块 %1$s 吗?</string>
|
||||
<string name="kpm_uninstall_success">卸载成功</string>
|
||||
<string name="kpm_uninstall_failed">卸载失败</string>
|
||||
<string name="kpm_install">加载 kpm 模块</string>
|
||||
<string name="kpm_install_confirm">确认加载吗?</string>
|
||||
<string name="kpm_install">选择安装</string>
|
||||
<string name="kpm_install_success">加载 kpm 模块成功</string>
|
||||
<string name="kpm_install_failed">加载 kpm 模块失败</string>
|
||||
<string name="home_kpm_version">KPM 版本</string>
|
||||
@@ -252,4 +250,12 @@
|
||||
<string name="home_ContributionCard_kernelsu">SukiSU Ultra 展望</string>
|
||||
<string name="home_click_to_ContributionCard_kernelsu">SukiSU Ultra 未来将会成为一个相对独立的 KSU 分支,但是依然感谢官方 KernelSU 和 MKSU 等做出的贡献</string>
|
||||
<string name="custom_settings">个性化设置</string>
|
||||
<string name="kpm_install_mode">安装</string>
|
||||
<string name="kpm_install_mode_load">加载</string>
|
||||
<string name="kpm_install_mode_embed">嵌入</string>
|
||||
<string name="kpm_install_mode_description">请选择模块安装模式:\n\n加载:临时加载模块\n嵌入:永久安装到系统</string>
|
||||
<string name="snackbar_failed_to_check_module_file">无法检查模块文件是否存在</string>
|
||||
<string name="confirm_uninstall_title">确认卸载</string>
|
||||
<string name="confirm_uninstall_confirm">删除</string>
|
||||
<string name="confirm_uninstall_dismiss">取消</string>
|
||||
</resources>
|
||||
|
||||
@@ -232,11 +232,9 @@
|
||||
<string name="kpm_version">releases</string>
|
||||
<string name="kpm_author">author</string>
|
||||
<string name="kpm_uninstall">uninstallation</string>
|
||||
<string name="kpm_uninstall_confirm">Determine the kernel module to uninstall: %1$s ?</string>
|
||||
<string name="kpm_uninstall_success">Uninstalled successfully</string>
|
||||
<string name="kpm_uninstall_failed">Failed to uninstall</string>
|
||||
<string name="kpm_install">Load the kpm module</string>
|
||||
<string name="kpm_install_confirm">Confirm Load?</string>
|
||||
<string name="kpm_install">Select Installation</string>
|
||||
<string name="kpm_install_success">Load of kpm module successful</string>
|
||||
<string name="kpm_install_failed">Load of kpm module failed</string>
|
||||
<string name="kpm_args">kpm parameters</string>
|
||||
@@ -255,4 +253,13 @@
|
||||
<string name="kernel_patched">Kernel not patched</string>
|
||||
<string name="kernel_not_enabled">Kernel not configured</string>
|
||||
<string name="custom_settings">Custom settings</string>
|
||||
<string name="kpm_install_mode">install</string>
|
||||
<string name="kpm_install_mode_load">Load</string>
|
||||
<string name="kpm_install_mode_embed">embed</string>
|
||||
<string name="kpm_install_mode_description">Please select the module installation mode: \n\nLoad: Temporarily load the module \nEmbedded: Permanently install into the system</string>
|
||||
<string name="log_failed_to_check_module_file">Failed to check module file existence</string>
|
||||
<string name="snackbar_failed_to_check_module_file">Unable to check if module file exists</string>
|
||||
<string name="confirm_uninstall_title">Confirm uninstallation</string>
|
||||
<string name="confirm_uninstall_confirm">removing</string>
|
||||
<string name="confirm_uninstall_dismiss">abolish</string>
|
||||
</resources>
|
||||
|
||||
@@ -6,6 +6,7 @@ edition = "2024"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
notify = "6.1"
|
||||
anyhow = "1"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
const_format = "0.2"
|
||||
|
||||
@@ -5,10 +5,13 @@ use anyhow::{Context, Result};
|
||||
use log::{info, warn};
|
||||
use rustix::fs::{MountFlags, mount};
|
||||
use std::path::Path;
|
||||
use crate::kpm;
|
||||
|
||||
pub fn on_post_data_fs() -> Result<()> {
|
||||
ksucalls::report_post_fs_data();
|
||||
|
||||
kpm::start_kpm_watcher()?;
|
||||
|
||||
utils::umask(0);
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -98,6 +101,13 @@ pub fn on_post_data_fs() -> Result<()> {
|
||||
|
||||
run_stage("post-mount", true);
|
||||
|
||||
for entry in std::fs::read_dir(kpm::KPM_DIR)? {
|
||||
let path = entry?.path();
|
||||
if path.extension().is_some_and(|ext| ext == "kpm") {
|
||||
let _ = kpm::load_kpm(&path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
122
userspace/ksud/src/kpm.rs
Normal file
122
userspace/ksud/src/kpm.rs
Normal file
@@ -0,0 +1,122 @@
|
||||
use anyhow::Result;
|
||||
use notify::{Watcher, RecursiveMode};
|
||||
use std::path::Path;
|
||||
use std::fs;
|
||||
use anyhow::anyhow;
|
||||
|
||||
pub const KPM_DIR: &str = "/data/adb/kpm";
|
||||
pub const KPMMGR_PATH: &str = "/data/adb/ksu/bin/kpmmgr";
|
||||
|
||||
|
||||
pub fn ensure_kpm_dir() -> Result<()> {
|
||||
if !Path::new(KPM_DIR).exists() {
|
||||
fs::create_dir_all(KPM_DIR)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn start_kpm_watcher() -> Result<()> {
|
||||
ensure_kpm_dir()?;
|
||||
load_existing_kpms()?;
|
||||
|
||||
// 检查是否处于安全模式
|
||||
if crate::utils::is_safe_mode() {
|
||||
log::warn!("The system is in safe mode and is deleting all KPM modules...");
|
||||
if let Err(e) = remove_all_kpms() {
|
||||
log::error!("Error deleting all KPM modules: {}", e);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut watcher = notify::recommended_watcher(|res| {
|
||||
match res {
|
||||
Ok(event) => handle_kpm_event(event),
|
||||
Err(e) => log::error!("monitoring error: {:?}", e),
|
||||
}
|
||||
})?;
|
||||
|
||||
watcher.watch(Path::new(KPM_DIR), RecursiveMode::NonRecursive)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn handle_kpm_event(event: notify::Event) {
|
||||
match event.kind {
|
||||
notify::EventKind::Create(_) => {
|
||||
event.paths.iter().for_each(|path| {
|
||||
if path.extension().is_some_and(|ext| ext == "kpm") {
|
||||
let _ = load_kpm(path);
|
||||
}
|
||||
});
|
||||
}
|
||||
notify::EventKind::Remove(_) => {
|
||||
event.paths.iter().for_each(|path| {
|
||||
if let Some(name) = path.file_stem() {
|
||||
let _ = unload_kpm(name.to_string_lossy().as_ref());
|
||||
}
|
||||
});
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_kpm(path: &Path) -> Result<()> {
|
||||
let status = std::process::Command::new(KPMMGR_PATH)
|
||||
.args(["load", path.to_str().unwrap(), ""])
|
||||
.status()?;
|
||||
|
||||
if status.success() {
|
||||
log::info!("Loaded KPM: {}", path.display());
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn unload_kpm(name: &str) -> Result<()> {
|
||||
let status = std::process::Command::new(KPMMGR_PATH)
|
||||
.args(["unload", name])
|
||||
.status()
|
||||
.map_err(|e| anyhow!("Failed to execute kpmmgr: {}", e))?;
|
||||
|
||||
let kpm_path = Path::new(KPM_DIR).join(format!("{}.kpm", name));
|
||||
if kpm_path.exists() {
|
||||
fs::remove_file(&kpm_path)
|
||||
.map_err(|e| anyhow!("Failed to delete KPM file: {}", e))
|
||||
.map(|_| log::info!("Deleted KPM file: {}", kpm_path.display()))?;
|
||||
}
|
||||
|
||||
if status.success() {
|
||||
log::info!("Successfully unloaded KPM: {}", name);
|
||||
} else {
|
||||
log::warn!("KPM unloading may have failed: {}", name);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn remove_all_kpms() -> Result<()> {
|
||||
ensure_kpm_dir()?;
|
||||
|
||||
for entry in fs::read_dir(KPM_DIR)? {
|
||||
let path = entry?.path();
|
||||
if path.extension().is_some_and(|ext| ext == "kpm") {
|
||||
if let Some(name) = path.file_stem() {
|
||||
unload_kpm(name.to_string_lossy().as_ref())
|
||||
.unwrap_or_else(|e| log::error!("Failed to remove KPM: {}", e));
|
||||
let _ = fs::remove_file(&path);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// 加载所有现有的 KPM 模块
|
||||
pub fn load_existing_kpms() -> Result<()> {
|
||||
ensure_kpm_dir()?;
|
||||
|
||||
for entry in fs::read_dir(KPM_DIR)? {
|
||||
let path = entry?.path();
|
||||
if path.extension().map_or(false, |ext| ext == "kpm") {
|
||||
let _ = load_kpm(&path);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -14,6 +14,7 @@ mod restorecon;
|
||||
mod sepolicy;
|
||||
mod su;
|
||||
mod utils;
|
||||
mod kpm;
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
cli::run()
|
||||
|
||||
Reference in New Issue
Block a user