manager: Add configure susfs uname value in more settings

Signed-off-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-06-14 01:10:40 +08:00
parent d7a5e80d34
commit d6c8ef3737
6 changed files with 811 additions and 1 deletions

Binary file not shown.

View File

@@ -0,0 +1,327 @@
package com.sukisu.ultra.ui.component
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AutoMode
import androidx.compose.material.icons.filled.RestoreFromTrash
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.util.SuSFSManager
import kotlinx.coroutines.launch
/**
* SuSFS配置对话框
*/
@Composable
fun SuSFSConfigDialog(
onDismiss: () -> Unit
) {
val context = LocalContext.current
val coroutineScope = rememberCoroutineScope()
var unameValue by remember { mutableStateOf("") }
var isLoading by remember { mutableStateOf(false) }
var showConfirmReset by remember { mutableStateOf(false) }
var autoStartEnabled by remember { mutableStateOf(false) }
var lastAppliedValue by remember { mutableStateOf("") }
// 实时判断是否可以启用开机自启动
val canEnableAutoStart by remember {
derivedStateOf {
unameValue.trim().isNotBlank() && unameValue.trim() != "default"
}
}
// 加载当前配置
LaunchedEffect(Unit) {
unameValue = SuSFSManager.getUnameValue(context)
autoStartEnabled = SuSFSManager.isAutoStartEnabled(context)
lastAppliedValue = SuSFSManager.getLastAppliedValue(context)
}
// 当输入值变化时,自动调整开机自启动状态
LaunchedEffect(canEnableAutoStart) {
if (!canEnableAutoStart && autoStartEnabled) {
// 如果输入值变为default或空自动关闭开机自启动
autoStartEnabled = false
SuSFSManager.configureAutoStart(context, false)
}
}
// 重置确认对话框
if (showConfirmReset) {
AlertDialog(
onDismissRequest = { showConfirmReset = false },
title = {
Text(
text = stringResource(R.string.susfs_reset_confirm_title),
style = MaterialTheme.typography.titleMedium
)
},
text = {
Text(stringResource(R.string.susfs_reset_confirm_message))
},
confirmButton = {
TextButton(
onClick = {
showConfirmReset = false
coroutineScope.launch {
isLoading = true
if (SuSFSManager.resetToDefault(context)) {
unameValue = "default"
lastAppliedValue = "default"
autoStartEnabled = false
}
isLoading = false
}
}
) {
Text(stringResource(R.string.susfs_reset_confirm))
}
},
dismissButton = {
TextButton(
onClick = { showConfirmReset = false }
) {
Text(stringResource(R.string.cancel))
}
}
)
}
AlertDialog(
onDismissRequest = onDismiss,
title = {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.Settings,
contentDescription = null,
tint = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.width(8.dp))
Text(
text = stringResource(R.string.susfs_config_title),
style = MaterialTheme.typography.titleLarge,
fontWeight = FontWeight.Bold
)
}
},
text = {
Column(
modifier = Modifier.fillMaxWidth()
) {
// 说明卡片
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.5f)
),
shape = RoundedCornerShape(8.dp)
) {
Column(
modifier = Modifier.padding(12.dp)
) {
Text(
text = stringResource(R.string.susfs_config_description),
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colorScheme.primary
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = stringResource(R.string.susfs_config_description_text),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
}
}
Spacer(modifier = Modifier.height(16.dp))
// 输入框
OutlinedTextField(
value = unameValue,
onValueChange = { unameValue = it },
label = { Text(stringResource(R.string.susfs_uname_label)) },
placeholder = { Text(stringResource(R.string.susfs_uname_placeholder)) },
modifier = Modifier.fillMaxWidth(),
enabled = !isLoading,
singleLine = true
)
Spacer(modifier = Modifier.height(8.dp))
// 当前值显示
Text(
text = stringResource(R.string.susfs_current_value, SuSFSManager.getUnameValue(context)),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant
)
Spacer(modifier = Modifier.height(16.dp))
// 开机自启动开关
Card(
modifier = Modifier.fillMaxWidth(),
colors = CardDefaults.cardColors(
containerColor = if (canEnableAutoStart) {
MaterialTheme.colorScheme.surface
} else {
MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.3f)
}
),
shape = RoundedCornerShape(8.dp)
) {
Row(
modifier = Modifier
.fillMaxWidth()
.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Column(
modifier = Modifier.weight(1f)
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
Icon(
imageVector = Icons.Default.AutoMode,
contentDescription = null,
tint = if (canEnableAutoStart) {
MaterialTheme.colorScheme.primary
} else {
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
},
modifier = Modifier.padding(end = 8.dp)
)
Text(
text = stringResource(R.string.susfs_autostart_title),
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Medium,
color = if (canEnableAutoStart) {
MaterialTheme.colorScheme.onSurface
} else {
MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.5f)
}
)
}
Spacer(modifier = Modifier.height(4.dp))
Text(
text = if (canEnableAutoStart) {
stringResource(R.string.susfs_autostart_description)
} else {
stringResource(R.string.susfs_autostart_tis)
},
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(
alpha = if (canEnableAutoStart) 1f else 0.5f
)
)
}
Switch(
checked = autoStartEnabled,
onCheckedChange = { enabled ->
if (canEnableAutoStart) {
coroutineScope.launch {
isLoading = true
if (SuSFSManager.configureAutoStart(context, enabled)) {
autoStartEnabled = enabled
}
isLoading = false
}
}
},
enabled = !isLoading && canEnableAutoStart
)
}
}
Spacer(modifier = Modifier.height(16.dp))
// 重置按钮
OutlinedButton(
onClick = { showConfirmReset = true },
modifier = Modifier.fillMaxWidth(),
enabled = !isLoading
) {
Icon(
imageVector = Icons.Default.RestoreFromTrash,
contentDescription = null,
modifier = Modifier.padding(end = 8.dp)
)
Text(stringResource(R.string.susfs_reset_to_default))
}
}
},
confirmButton = {
Row(
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
TextButton(
onClick = onDismiss,
enabled = !isLoading
) {
Text(stringResource(R.string.cancel))
}
Button(
onClick = {
if (unameValue.isNotBlank()) {
coroutineScope.launch {
isLoading = true
val success = SuSFSManager.setUname(context, unameValue.trim())
if (success) {
lastAppliedValue = unameValue.trim()
onDismiss()
}
isLoading = false
}
}
},
enabled = !isLoading && unameValue.isNotBlank()
) {
Text(
stringResource(R.string.susfs_apply)
)
}
}
},
dismissButton = null
)
}

View File

@@ -0,0 +1,399 @@
package com.sukisu.ultra.ui.util
import android.content.Context
import android.content.SharedPreferences
import android.widget.Toast
import com.sukisu.ultra.R
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.FileOutputStream
import java.io.IOException
import java.io.File
/**
* SuSFS 配置管理器
* 用于管理SuSFS相关的配置和命令执行
*/
object SuSFSManager {
private const val PREFS_NAME = "susfs_config"
private const val KEY_UNAME_VALUE = "uname_value"
private const val KEY_IS_ENABLED = "is_enabled"
private const val KEY_AUTO_START_ENABLED = "auto_start_enabled"
private const val KEY_LAST_APPLIED_VALUE = "last_applied_value"
private const val SUSFS_BINARY_NAME = "ksu_susfs"
private const val DEFAULT_UNAME = "default"
private const val STARTUP_SCRIPT_PATH = "/data/adb/service.d/susfs_startup.sh"
private const val SUSFS_TARGET_PATH = "/data/adb/ksu/bin/$SUSFS_BINARY_NAME"
/**
* 获取Root Shell实例
*/
private fun getRootShell(): Shell {
return Shell.getShell()
}
/**
* 获取SuSFS配置的SharedPreferences
*/
private fun getPrefs(context: Context): SharedPreferences {
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
}
/**
* 保存uname值
*/
fun saveUnameValue(context: Context, value: String) {
getPrefs(context).edit().apply {
putString(KEY_UNAME_VALUE, value)
apply()
}
}
/**
* 获取保存的uname值
*/
fun getUnameValue(context: Context): String {
return getPrefs(context).getString(KEY_UNAME_VALUE, DEFAULT_UNAME) ?: DEFAULT_UNAME
}
/**
* 保存最后应用的值
*/
private fun saveLastAppliedValue(context: Context, value: String) {
getPrefs(context).edit().apply {
putString(KEY_LAST_APPLIED_VALUE, value)
apply()
}
}
/**
* 获取最后应用的值
*/
fun getLastAppliedValue(context: Context): String {
return getPrefs(context).getString(KEY_LAST_APPLIED_VALUE, DEFAULT_UNAME) ?: DEFAULT_UNAME
}
/**
* 保存SuSFS启用状态
*/
fun setEnabled(context: Context, enabled: Boolean) {
getPrefs(context).edit().apply {
putBoolean(KEY_IS_ENABLED, enabled)
apply()
}
}
/**
* 设置开机自启动状态
*/
fun setAutoStartEnabled(context: Context, enabled: Boolean) {
getPrefs(context).edit().apply {
putBoolean(KEY_AUTO_START_ENABLED, enabled)
apply()
}
}
/**
* 获取开机自启动状态
*/
fun isAutoStartEnabled(context: Context): Boolean {
return getPrefs(context).getBoolean(KEY_AUTO_START_ENABLED, false)
}
/**
* 从assets复制ksu_susfs文件到/data/adb/ksu/bin/
*/
private suspend fun copyBinaryFromAssets(context: Context): String? = withContext(Dispatchers.IO) {
try {
val inputStream = context.assets.open(SUSFS_BINARY_NAME)
val tempFile = File(context.cacheDir, SUSFS_BINARY_NAME)
FileOutputStream(tempFile).use { outputStream ->
inputStream.copyTo(outputStream)
}
// 创建目标目录并复制文件到/data/adb/ksu/bin/
val shell = getRootShell()
val commands = arrayOf(
"cp '${tempFile.absolutePath}' '$SUSFS_TARGET_PATH'",
"chmod 755 '$SUSFS_TARGET_PATH'",
)
var success = true
for (command in commands) {
val result = shell.newJob().add(command).exec()
if (!result.isSuccess) {
success = false
break
}
}
// 清理临时文件
tempFile.delete()
if (success) {
val verifyResult = shell.newJob().add("test -f '$SUSFS_TARGET_PATH'").exec()
if (verifyResult.isSuccess) {
SUSFS_TARGET_PATH
} else {
null
}
} else {
null
}
} catch (e: IOException) {
e.printStackTrace()
null
}
}
/**
* 创建开机自启动脚本
*/
private suspend fun createStartupScript(unameValue: String): Boolean = withContext(Dispatchers.IO) {
try {
val scriptContent = """#!/system/bin/sh
# SuSFS 开机自启动脚本
# 由 KernelSU Manager 自动生成
# 等待系统完全启动
sleep 30
# 检查二进制文件是否存在
if [ -f "$SUSFS_TARGET_PATH" ]; then
# 执行 SuSFS setUname 命令
$SUSFS_TARGET_PATH set_uname '$unameValue' '$DEFAULT_UNAME'
# 记录日志
echo "\$(date): SuSFS setUname executed with value: $unameValue" >> /data/adb/ksu/log/susfs_startup.log
else
echo "\$(date): SuSFS binary not found at $SUSFS_TARGET_PATH" >> /data/adb/ksu/log/susfs_startup.log
fi
"""
val shell = getRootShell()
val commands = arrayOf(
"mkdir -p /data/adb/service.d",
"cat > $STARTUP_SCRIPT_PATH << 'EOF'\n$scriptContent\nEOF",
"chmod 755 $STARTUP_SCRIPT_PATH"
)
var success = true
for (command in commands) {
val result = shell.newJob().add(command).exec()
if (!result.isSuccess) {
success = false
break
}
}
success
} catch (e: Exception) {
e.printStackTrace()
false
}
}
/**
* 删除开机自启动脚本
*/
private suspend fun removeStartupScript(): Boolean = withContext(Dispatchers.IO) {
try {
val shell = getRootShell()
val result = shell.newJob().add("rm -f $STARTUP_SCRIPT_PATH").exec()
result.isSuccess
} catch (e: Exception) {
e.printStackTrace()
false
}
}
/**
* 执行SuSFS命令设置uname
*/
suspend fun setUname(context: Context, unameValue: String): Boolean = withContext(Dispatchers.IO) {
try {
// 首先复制二进制文件到/data/adb/ksu/bin/
val binaryPath = copyBinaryFromAssets(context)
if (binaryPath == null) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_binary_not_found),
Toast.LENGTH_SHORT
).show()
}
return@withContext false
}
// 构建命令
val command = "$binaryPath set_uname '$unameValue' '$DEFAULT_UNAME'"
// 执行命令
val result = getRootShell().newJob().add(command).exec()
if (result.isSuccess) {
// 保存配置
saveUnameValue(context, unameValue)
saveLastAppliedValue(context, unameValue)
setEnabled(context, true)
// 如果开启了开机自启动,更新启动脚本
if (isAutoStartEnabled(context)) {
createStartupScript(unameValue)
}
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_uname_set_success, unameValue),
Toast.LENGTH_SHORT
).show()
}
true
} else {
withContext(Dispatchers.Main) {
val errorOutput = result.out.joinToString("\n") + "\n" + result.err.joinToString("\n")
Toast.makeText(
context,
context.getString(R.string.susfs_command_failed) + "\n$errorOutput",
Toast.LENGTH_LONG
).show()
}
false
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_command_error, e.message ?: "Unknown error"),
Toast.LENGTH_SHORT
).show()
}
false
}
}
/**
* 配置开机自启动
*/
suspend fun configureAutoStart(context: Context, enabled: Boolean): Boolean = withContext(Dispatchers.IO) {
try {
if (enabled) {
// 启用开机自启动
val lastValue = getLastAppliedValue(context)
if (lastValue == DEFAULT_UNAME) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_no_config_to_autostart),
Toast.LENGTH_SHORT
).show()
}
return@withContext false
}
// 确保二进制文件存在于目标位置
val shell = getRootShell()
val checkResult = shell.newJob().add("test -f '$SUSFS_TARGET_PATH'").exec()
if (!checkResult.isSuccess) {
// 如果不存在,尝试复制
val binaryPath = copyBinaryFromAssets(context)
if (binaryPath == null) {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_binary_not_found),
Toast.LENGTH_SHORT
).show()
}
return@withContext false
}
}
val success = createStartupScript(lastValue)
if (success) {
setAutoStartEnabled(context, true)
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_autostart_enabled),
Toast.LENGTH_SHORT
).show()
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_autostart_enable_failed),
Toast.LENGTH_SHORT
).show()
}
}
success
} else {
// 禁用开机自启动
val success = removeStartupScript()
if (success) {
setAutoStartEnabled(context, false)
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_autostart_disabled),
Toast.LENGTH_SHORT
).show()
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_autostart_disable_failed),
Toast.LENGTH_SHORT
).show()
}
}
success
}
} catch (e: Exception) {
e.printStackTrace()
withContext(Dispatchers.Main) {
Toast.makeText(
context,
context.getString(R.string.susfs_autostart_error, e.message ?: "Unknown error"),
Toast.LENGTH_SHORT
).show()
}
false
}
}
/**
* 重置为默认值
*/
suspend fun resetToDefault(context: Context): Boolean {
val success = setUname(context, DEFAULT_UNAME)
if (success) {
// 重置时清除最后应用的值
saveLastAppliedValue(context, DEFAULT_UNAME)
// 如果开启了开机自启动,需要禁用它
if (isAutoStartEnabled(context)) {
configureAutoStart(context, false)
}
}
return success
}
/**
* 检查ksu_susfs文件是否存在于assets中
*/
fun isBinaryAvailable(context: Context): Boolean {
return try {
context.assets.open(SUSFS_BINARY_NAME).use { true }
} catch (_: IOException) {
false
}
}
}

View File

@@ -63,6 +63,7 @@ import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.ImageEditorDialog
import com.sukisu.ultra.ui.component.KsuIsValid
import com.sukisu.ultra.ui.component.SuSFSConfigDialog
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.*
import com.sukisu.ultra.ui.util.*
@@ -145,6 +146,7 @@ fun MoreSettingsScreen(
var showThemeColorDialog by remember { mutableStateOf(false) }
var showDpiConfirmDialog by remember { mutableStateOf(false) }
var showImageEditor by remember { mutableStateOf(false) }
var showSuSFSConfigDialog by remember { mutableStateOf(false) }
// 主题模式选项
val themeOptions = listOf(
@@ -475,6 +477,13 @@ fun MoreSettingsScreen(
)
}
// SuSFS配置对话框
if (showSuSFSConfigDialog) {
SuSFSConfigDialog(
onDismiss = { showSuSFSConfigDialog = false }
)
}
// 主题模式选择对话框
if (showThemeModeDialog) {
SingleChoiceDialog(
@@ -1120,7 +1129,20 @@ fun MoreSettingsScreen(
)
}
// SuSFS 配置(仅在支持时显示)
// SuSFS 配置(仅在支持时显示
if (getSuSFS() == "Supported" && SuSFSManager.isBinaryAvailable(context)) {
SettingItem(
icon = Icons.Default.Settings,
title = stringResource(R.string.susfs_config_setting_title),
subtitle = stringResource(
R.string.susfs_config_setting_summary,
SuSFSManager.getUnameValue(context)
),
onClick = { showSuSFSConfigDialog = true }
)
}
// SuSFS 开关(仅在支持时显示)
val suSFS = getSuSFS()
val isSUS_SU = getSuSFSFeatures()
if (suSFS == "Supported" && isSUS_SU == "CONFIG_KSU_SUSFS_SUS_SU") {

View File

@@ -396,4 +396,35 @@
<string name="menu_options">菜单选项</string>
<string name="sort_options">排序方式</string>
<string name="app_categories">应用类型选择</string>
<!-- SuSFS Configuration -->
<string name="susfs_config_title">SuSFS 配置</string>
<string name="susfs_config_description">配置说明</string>
<string name="susfs_config_description_text">此功能允许您自定义 SuSFS 的 uname 值。输入您想要设置的值,点击应用即可生效</string>
<string name="susfs_uname_label">Uname 值</string>
<string name="susfs_uname_placeholder">请输入自定义 uname 值</string>
<string name="susfs_current_value">当前值: %s</string>
<string name="susfs_reset_to_default">重置为默认值</string>
<string name="susfs_apply">应用</string>
<!-- SuSFS Reset Confirmation -->
<string name="susfs_reset_confirm_title">确认重置</string>
<string name="susfs_reset_confirm_message">确定要将 SuSFS uname 重置为默认值吗?此操作不可撤销。</string>
<string name="susfs_reset_confirm">确认重置</string>
<!-- SuSFS Toast Messages -->
<string name="susfs_binary_not_found">无法找到 ksu_susfs 文件</string>
<string name="susfs_command_failed">SuSFS 命令执行失败</string>
<string name="susfs_command_error">执行 SuSFS 命令时出错: %s</string>
<string name="susfs_uname_set_success">SuSFS uname 设置成功: %s</string>
<!-- SuSFS Settings Item -->
<string name="susfs_config_setting_title">SuSFS 配置</string>
<string name="susfs_config_setting_summary">配置 SuSFS 的 uname 值 (当前: %s)</string>
<!-- 开机自启动相关 -->
<string name="susfs_autostart_title">开机自启动</string>
<string name="susfs_autostart_description">系统启动时自动应用 uname 配置</string>
<string name="susfs_autostart_enabled">开机自启动已启用</string>
<string name="susfs_autostart_disabled">开机自启动已禁用</string>
<string name="susfs_autostart_enable_failed">启用开机自启动失败</string>
<string name="susfs_autostart_disable_failed">禁用开机自启动失败</string>
<string name="susfs_autostart_error">开机自启动配置错误: %s</string>
<string name="susfs_no_config_to_autostart">没有可用的配置进行开机自启动</string>
<string name="susfs_autostart_tis">需要输入非默认值才能启用开机自启动</string>
</resources>

View File

@@ -398,4 +398,35 @@
<string name="menu_options">Menu Options</string>
<string name="sort_options">Sort by</string>
<string name="app_categories">Application Type Selection</string>
<!-- SuSFS Configuration -->
<string name="susfs_config_title">SuSFS Configuration</string>
<string name="susfs_config_description">Configuration Description</string>
<string name="susfs_config_description_text">This feature allows you to customize the SuSFS uname value. Enter the value you want to set and click Apply to take effect.</string>
<string name="susfs_uname_label">Uname Value</string>
<string name="susfs_uname_placeholder">Please enter custom uname value</string>
<string name="susfs_current_value">Current value: %s</string>
<string name="susfs_reset_to_default">Reset to Default</string>
<string name="susfs_apply">Apply</string>
<!-- SuSFS Reset Confirmation -->
<string name="susfs_reset_confirm_title">Confirm Reset</string>
<string name="susfs_reset_confirm_message">Are you sure you want to reset SuSFS uname to default value? This action cannot be undone.</string>
<string name="susfs_reset_confirm">Confirm Reset</string>
<!-- SuSFS Toast Messages -->
<string name="susfs_binary_not_found">Cannot find ksu_susfs file</string>
<string name="susfs_command_failed">SuSFS command execution failed</string>
<string name="susfs_command_error">Error executing SuSFS command: %s</string>
<string name="susfs_uname_set_success">SuSFS uname set successfully: %s</string>
<!-- SuSFS Settings Item -->
<string name="susfs_config_setting_title">SuSFS Configuration</string>
<string name="susfs_config_setting_summary">Configure SuSFS uname value (Current: %s)</string>
<!-- 开机自启动相关 -->
<string name="susfs_autostart_title">boot-up</string>
<string name="susfs_autostart_description">Automatic application of uname configuration at system startup</string>
<string name="susfs_autostart_enabled">Boot Self-Start is enabled</string>
<string name="susfs_autostart_disabled">Boot Self-Start is disabled</string>
<string name="susfs_autostart_enable_failed">Failed to enable boot self-start</string>
<string name="susfs_autostart_disable_failed">Failure to disable boot-up</string>
<string name="susfs_autostart_error">Boot-up misconfiguration: %s</string>
<string name="susfs_no_config_to_autostart">There is no available configuration for boot self-start</string>
<string name="susfs_autostart_tis">Need to enter a non-default value to enable bootstrapping</string>
</resources>