Step 5-1: Move the KPM interface to the settings

- Avoid multiple page re-rendering
- Add hook type information
- Clean up code
This commit is contained in:
ShirkNeko
2025-11-20 18:38:53 +08:00
parent 6826406494
commit 385f4ab2c5
12 changed files with 139 additions and 125 deletions

View File

@@ -335,11 +335,6 @@ NativeBridge(getUserName, jstring, jint uid) {
return NULL; return NULL;
} }
// Check if KPM is enabled
NativeBridgeNP(isKPMEnabled, jboolean) {
return is_KPM_enable();
}
// Get HOOK type // Get HOOK type
NativeBridgeNP(getHookType, jstring) { NativeBridgeNP(getHookType, jstring) {
char hook_type[32] = { 0 }; char hook_type[32] = { 0 };

View File

@@ -259,14 +259,6 @@ void get_full_version(char* buff) {
} }
} }
bool is_KPM_enable(void) {
struct ksu_enable_kpm_cmd cmd = {};
if (ksuctl(KSU_IOCTL_ENABLE_KPM, &cmd) == 0 && cmd.enabled) {
return true;
}
return legacy_is_KPM_enable();
}
void get_hook_type(char *buff) { void get_hook_type(char *buff) {
struct ksu_hook_type_cmd cmd = {0}; struct ksu_hook_type_cmd cmd = {0};
if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) { if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) {

View File

@@ -229,10 +229,6 @@ struct ksu_hook_type_cmd {
char hook_type[32]; // Output: hook type string char hook_type[32]; // Output: hook type string
}; };
struct ksu_enable_kpm_cmd {
uint8_t enabled; // Output: true if KPM is enabled
};
struct ksu_dynamic_manager_cmd { struct ksu_dynamic_manager_cmd {
struct dynamic_manager_user_config config; // Input/Output: dynamic manager config struct dynamic_manager_user_config config; // Input/Output: dynamic manager config
}; };

View File

@@ -88,12 +88,6 @@ bool legacy_is_su_enabled() {
return enabled; return enabled;
} }
bool legacy_is_KPM_enable() {
int enabled = false;
ksuctl(CMD_ENABLE_KPM, &enabled, NULL);
return enabled;
}
bool legacy_get_hook_type(char* hook_type, size_t size) { bool legacy_get_hook_type(char* hook_type, size_t size) {
if (hook_type == NULL || size == 0) { if (hook_type == NULL || size == 0) {
return false; return false;

View File

@@ -121,8 +121,6 @@ object Natives {
*/ */
external fun isSuLogEnabled(): Boolean external fun isSuLogEnabled(): Boolean
external fun setSuLogEnabled(enabled: Boolean): Boolean external fun setSuLogEnabled(enabled: Boolean): Boolean
external fun isKPMEnabled(): Boolean
external fun getHookType(): String external fun getHookType(): String
/** /**

View File

@@ -1,7 +1,6 @@
package com.sukisu.ultra.ui package com.sukisu.ultra.ui
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.compose.ui.graphics.Color
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
@@ -31,6 +30,7 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.navigation.NavBackStackEntry import androidx.navigation.NavBackStackEntry
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.ramcosta.composedestinations.DestinationsNavHost import com.ramcosta.composedestinations.DestinationsNavHost
@@ -47,13 +47,11 @@ import kotlinx.coroutines.launch
import com.sukisu.ultra.Natives import com.sukisu.ultra.Natives
import com.sukisu.ultra.ui.component.BottomBar import com.sukisu.ultra.ui.component.BottomBar
import com.sukisu.ultra.ui.screen.HomePager import com.sukisu.ultra.ui.screen.HomePager
import com.sukisu.ultra.ui.screen.KpmScreen
import com.sukisu.ultra.ui.screen.ModulePager import com.sukisu.ultra.ui.screen.ModulePager
import com.sukisu.ultra.ui.screen.SettingPager import com.sukisu.ultra.ui.screen.SettingPager
import com.sukisu.ultra.ui.screen.SuperUserPager import com.sukisu.ultra.ui.screen.SuperUserPager
import com.sukisu.ultra.ui.theme.KernelSUTheme import com.sukisu.ultra.ui.theme.KernelSUTheme
import com.sukisu.ultra.ui.util.install import com.sukisu.ultra.ui.util.install
import com.sukisu.ultra.ui.util.rememberKpmAvailable
import top.yukonga.miuix.kmp.basic.Scaffold import top.yukonga.miuix.kmp.basic.Scaffold
import top.yukonga.miuix.kmp.theme.MiuixTheme import top.yukonga.miuix.kmp.theme.MiuixTheme
@@ -94,6 +92,7 @@ class MainActivity : ComponentActivity() {
android.graphics.Color.TRANSPARENT android.graphics.Color.TRANSPARENT
) { darkMode }, ) { darkMode },
) )
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key -> val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
when (key) { when (key) {
"color_mode" -> colorMode = prefs.getInt("color_mode", 0) "color_mode" -> colorMode = prefs.getInt("color_mode", 0)
@@ -161,11 +160,7 @@ val LocalHandlePageChange = compositionLocalOf<(Int) -> Unit> { error("No handle
fun MainScreen(navController: DestinationsNavigator) { fun MainScreen(navController: DestinationsNavigator) {
val activity = LocalActivity.current val activity = LocalActivity.current
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val pagerState = rememberPagerState(initialPage = 0, pageCount = { 4 })
val isKpmAvailable = rememberKpmAvailable()
val pageCount = if (isKpmAvailable) 5 else 4
val pagerState = rememberPagerState(initialPage = 0, pageCount = { pageCount })
val hazeState = remember { HazeState() } val hazeState = remember { HazeState() }
val hazeStyle = HazeStyle( val hazeStyle = HazeStyle(
backgroundColor = MiuixTheme.colorScheme.background, backgroundColor = MiuixTheme.colorScheme.background,
@@ -193,7 +188,7 @@ fun MainScreen(navController: DestinationsNavigator) {
) { ) {
Scaffold( Scaffold(
bottomBar = { bottomBar = {
BottomBar(hazeState, hazeStyle, isKpmAvailable) BottomBar(hazeState, hazeStyle)
}, },
) { innerPadding -> ) { innerPadding ->
HorizontalPager( HorizontalPager(
@@ -202,26 +197,13 @@ fun MainScreen(navController: DestinationsNavigator) {
beyondViewportPageCount = 2, beyondViewportPageCount = 2,
userScrollEnabled = false userScrollEnabled = false
) { ) {
when { when (it) {
isKpmAvailable -> { 0 -> HomePager(pagerState, navController, innerPadding.calculateBottomPadding())
when (it) { 1 -> SuperUserPager(navController, innerPadding.calculateBottomPadding())
0 -> HomePager(pagerState, navController, innerPadding.calculateBottomPadding()) 2 -> ModulePager(navController, innerPadding.calculateBottomPadding())
1 -> KpmScreen(bottomInnerPadding = innerPadding.calculateBottomPadding()) 3 -> SettingPager(navController, innerPadding.calculateBottomPadding())
2 -> SuperUserPager(navController, innerPadding.calculateBottomPadding())
3 -> ModulePager(navController, innerPadding.calculateBottomPadding())
4 -> SettingPager(navController, innerPadding.calculateBottomPadding())
}
}
else -> {
when (it) {
0 -> HomePager(pagerState, navController, innerPadding.calculateBottomPadding())
1 -> SuperUserPager(navController, innerPadding.calculateBottomPadding())
2 -> ModulePager(navController, innerPadding.calculateBottomPadding())
3 -> SettingPager(navController, innerPadding.calculateBottomPadding())
}
}
} }
} }
} }
} }
} }

View File

@@ -2,7 +2,6 @@ package com.sukisu.ultra.ui.component
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Code
import androidx.compose.material.icons.rounded.Cottage import androidx.compose.material.icons.rounded.Cottage
import androidx.compose.material.icons.rounded.Extension import androidx.compose.material.icons.rounded.Extension
import androidx.compose.material.icons.rounded.Security import androidx.compose.material.icons.rounded.Security
@@ -28,8 +27,7 @@ import top.yukonga.miuix.kmp.basic.NavigationItem
@Composable @Composable
fun BottomBar( fun BottomBar(
hazeState: HazeState, hazeState: HazeState,
hazeStyle: HazeStyle, hazeStyle: HazeStyle
isKpmAvailable: Boolean = false
) { ) {
val isManager = Natives.isManager val isManager = Natives.isManager
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable() val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
@@ -39,24 +37,12 @@ fun BottomBar(
if (!fullFeatured) return if (!fullFeatured) return
val destinations = if (isKpmAvailable) { val item = BottomBarDestination.entries.mapIndexed { index, destination ->
BottomBarDestination.entries
} else {
BottomBarDestination.entries.filter { it != BottomBarDestination.KPM }
}
val item = destinations.mapIndexed { index, destination ->
NavigationItem( NavigationItem(
label = stringResource(destination.label), label = stringResource(destination.label),
icon = destination.icon, icon = destination.icon,
) )
} }
val bottomBarIndex = if (!isKpmAvailable) {
page.coerceIn(0, item.size - 1)
} else {
page.coerceIn(0, item.size - 1)
}
NavigationBar( NavigationBar(
modifier = Modifier modifier = Modifier
@@ -67,10 +53,8 @@ fun BottomBar(
}, },
color = Color.Transparent, color = Color.Transparent,
items = item, items = item,
selected = bottomBarIndex, selected = page,
onClick = { index -> onClick = handlePageChange
handlePageChange(index)
}
) )
} }
@@ -79,8 +63,7 @@ enum class BottomBarDestination(
val icon: ImageVector, val icon: ImageVector,
) { ) {
Home(R.string.home, Icons.Rounded.Cottage), Home(R.string.home, Icons.Rounded.Cottage),
KPM(R.string.kpm_title, Icons.Rounded.Code),
SuperUser(R.string.superuser, Icons.Rounded.Security), SuperUser(R.string.superuser, Icons.Rounded.Security),
Module(R.string.module, Icons.Rounded.Extension), Module(R.string.module, Icons.Rounded.Extension),
Setting(R.string.settings, Icons.Rounded.Settings) Setting(R.string.settings, Icons.Rounded.Settings)
} }

View File

@@ -37,11 +37,14 @@ import androidx.compose.material.icons.rounded.CheckCircleOutline
import androidx.compose.material.icons.rounded.ErrorOutline import androidx.compose.material.icons.rounded.ErrorOutline
import androidx.compose.material.icons.rounded.Link import androidx.compose.material.icons.rounded.Link
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -149,8 +152,6 @@ fun HomePager(
val lkmMode = ksuVersion?.let { val lkmMode = ksuVersion?.let {
if (kernelVersion.isGKI()) Natives.isLkmMode else null if (kernelVersion.isGKI()) Natives.isLkmMode else null
} }
val isKpmAvailable = rememberKpmAvailable()
Column( Column(
modifier = Modifier.padding(vertical = 12.dp), modifier = Modifier.padding(vertical = 12.dp),
@@ -179,12 +180,12 @@ fun HomePager(
}, },
onClickSuperuser = { onClickSuperuser = {
coroutineScope.launch { coroutineScope.launch {
pagerState.animateScrollToPage(getSuperuserPageIndex(isKpmAvailable)) pagerState.animateScrollToPage(1)
} }
}, },
onclickModule = { onclickModule = {
coroutineScope.launch { coroutineScope.launch {
pagerState.animateScrollToPage(getModulePageIndex(isKpmAvailable)) pagerState.animateScrollToPage(2)
} }
}, },
themeMode = themeMode themeMode = themeMode
@@ -609,6 +610,19 @@ fun DonateCard() {
private fun InfoCard() { private fun InfoCard() {
val manualHookText = stringResource(R.string.manual_hook) val manualHookText = stringResource(R.string.manual_hook)
val inlineHookText = stringResource(R.string.inline_hook) val inlineHookText = stringResource(R.string.inline_hook)
val TracepointHookText = stringResource(R.string.tracepoint_hook)
val unknownHookText = stringResource(R.string.selinux_status_unknown)
val susfsInfo = rememberSusfsInfo(manualHookText, inlineHookText)
val isSusfsSupported = susfsInfo.status == SusfsStatus.Supported
val hookTypeLabel = remember(manualHookText, inlineHookText, TracepointHookText) {
val localized = when (val rawType = Natives.getHookType()) {
"Manual" -> manualHookText
"Tracepoint" -> TracepointHookText
else -> rawType
}
localized.ifBlank { unknownHookText }
}
@Composable @Composable
fun InfoText( fun InfoText(
title: String, title: String,
@@ -632,23 +646,6 @@ private fun InfoCard() {
val context = LocalContext.current val context = LocalContext.current
val uname = Os.uname() val uname = Os.uname()
val managerVersion = getManagerVersion(context) val managerVersion = getManagerVersion(context)
val susfsPair by produceState(initialValue = "" to "") {
value = withContext(Dispatchers.IO) {
val rawFeature = getSuSFSFeatures()
val status = if (rawFeature.isNotEmpty() && !rawFeature.startsWith("[-]")) "Supported" else rawFeature
if (status == "Supported") {
val version = getSuSFSVersion()
val hook = when (Natives.getHookType()) {
"Manual" -> "($manualHookText)"
"Inline" -> "($inlineHookText)"
else -> "(${Natives.getHookType()})"
}
status to "$version $hook".trim()
} else {
"" to ""
}
}
}
Card { Card {
Column( Column(
@@ -689,27 +686,26 @@ private fun InfoCard() {
) )
} }
} }
InfoText( if (isSusfsSupported) {
title = stringResource(R.string.home_fingerprint),
content = Build.FINGERPRINT
)
if (susfsPair.first == "Supported" && susfsPair.second.isNotEmpty()) {
InfoText(
title = stringResource(R.string.home_selinux_status),
content = getSELinuxStatus(),
)
InfoText( InfoText(
title = stringResource(R.string.home_susfs_version), title = stringResource(R.string.home_susfs_version),
content = susfsPair.second, content = susfsInfo.detail
bottomPadding = 0.dp
) )
} else { } else {
InfoText( InfoText(
title = stringResource(R.string.home_selinux_status), title = stringResource(R.string.hook_type),
content = getSELinuxStatus(), content = hookTypeLabel
bottomPadding = 0.dp
) )
} }
InfoText(
title = stringResource(R.string.home_selinux_status),
content = getSELinuxStatus(),
)
InfoText(
title = stringResource(R.string.home_fingerprint),
content = Build.FINGERPRINT,
bottomPadding = 0.dp
)
} }
} }
} }
@@ -720,10 +716,52 @@ fun getManagerVersion(context: Context): Pair<String, Long> {
return Pair(packageInfo.versionName!!, versionCode) return Pair(packageInfo.versionName!!, versionCode)
} }
fun getSuperuserPageIndex(isKpmAvailable: Boolean): Int { private enum class SusfsStatus {
return if (isKpmAvailable) 2 else 1 Idle, Loading, Supported, Unsupported, Error
} }
fun getModulePageIndex(isKpmAvailable: Boolean): Int { private data class SusfsInfoState(
return if (isKpmAvailable) 3 else 2 val status: SusfsStatus = SusfsStatus.Idle,
val detail: String = "",
)
@Composable
private fun rememberSusfsInfo(
manualHookLabel: String,
inlineHookLabel: String,
): SusfsInfoState {
var susfsInfo by remember { mutableStateOf(SusfsInfoState(status = SusfsStatus.Loading)) }
LaunchedEffect(manualHookLabel, inlineHookLabel) {
val info = withContext(Dispatchers.IO) {
runCatching {
val rawFeature = getSuSFSFeatures()
val supported = rawFeature.isNotEmpty() && !rawFeature.startsWith("[-]")
if (supported) {
val version = getSuSFSVersion().trim()
val hookLabel = when (val type = Natives.getHookType()) {
"Manual" -> manualHookLabel
"Inline" -> inlineHookLabel
else -> type
}.takeIf { it.isNotBlank() }?.let { "($it)" }.orEmpty()
SusfsInfoState(
status = SusfsStatus.Supported,
detail = listOf(version, hookLabel).filter { it.isNotBlank() }.joinToString(" ")
)
} else {
SusfsInfoState(
status = SusfsStatus.Unsupported,
detail = rawFeature
)
}
}.getOrElse {
SusfsInfoState(status = SusfsStatus.Error)
}
}
if (susfsInfo != info) {
susfsInfo = info
}
}
return susfsInfo
} }

View File

@@ -16,6 +16,7 @@ import androidx.compose.material.icons.rounded.Palette
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Adb import androidx.compose.material.icons.rounded.Adb
import androidx.compose.material.icons.rounded.BugReport import androidx.compose.material.icons.rounded.BugReport
import androidx.compose.material.icons.rounded.Code
import androidx.compose.material.icons.rounded.ContactPage import androidx.compose.material.icons.rounded.ContactPage
import androidx.compose.material.icons.rounded.Delete import androidx.compose.material.icons.rounded.Delete
import androidx.compose.material.icons.rounded.DeleteForever import androidx.compose.material.icons.rounded.DeleteForever
@@ -49,6 +50,7 @@ import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AboutScreenDestination import com.ramcosta.composedestinations.generated.destinations.AboutScreenDestination
import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplateScreenDestination
import com.ramcosta.composedestinations.generated.destinations.LogViewerDestination import com.ramcosta.composedestinations.generated.destinations.LogViewerDestination
import com.ramcosta.composedestinations.generated.destinations.KpmScreenDestination
import com.ramcosta.composedestinations.generated.destinations.PersonalizationDestination import com.ramcosta.composedestinations.generated.destinations.PersonalizationDestination
import com.ramcosta.composedestinations.generated.destinations.ToolsDestination import com.ramcosta.composedestinations.generated.destinations.ToolsDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator import com.ramcosta.composedestinations.navigation.DestinationsNavigator
@@ -64,6 +66,7 @@ import com.sukisu.ultra.ui.component.SendLogDialog
import com.sukisu.ultra.ui.component.UninstallDialog import com.sukisu.ultra.ui.component.UninstallDialog
import com.sukisu.ultra.ui.component.rememberLoadingDialog import com.sukisu.ultra.ui.component.rememberLoadingDialog
import com.sukisu.ultra.ui.util.execKsud import com.sukisu.ultra.ui.util.execKsud
import com.sukisu.ultra.ui.util.rememberKpmAvailable
import top.yukonga.miuix.kmp.basic.Card import top.yukonga.miuix.kmp.basic.Card
import top.yukonga.miuix.kmp.basic.Icon import top.yukonga.miuix.kmp.basic.Icon
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
@@ -94,6 +97,8 @@ fun SettingPager(
tint = HazeTint(colorScheme.surface.copy(0.8f)) tint = HazeTint(colorScheme.surface.copy(0.8f))
) )
val isKpmAvailable = rememberKpmAvailable()
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( TopAppBar(
@@ -265,6 +270,33 @@ fun SettingPager(
} }
} }
if (isKpmAvailable) {
Card(
modifier = Modifier
.padding(top = 12.dp)
.fillMaxWidth(),
) {
val kpmTitle = stringResource(id = R.string.kpm_title)
SuperArrow(
title = kpmTitle,
summary = stringResource(id = R.string.settings_kpm_summary),
leftAction = {
Icon(
Icons.Rounded.Code,
modifier = Modifier.padding(end = 16.dp),
contentDescription = kpmTitle,
tint = colorScheme.onBackground
)
},
onClick = {
navigator.navigate(KpmScreenDestination) {
launchSingleTop = true
}
}
)
}
}
KsuIsValid { KsuIsValid {
Card( Card(
modifier = Modifier modifier = Modifier

View File

@@ -12,7 +12,10 @@ import android.system.Os
import android.util.Log import android.util.Log
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState import androidx.compose.runtime.produceState
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import com.topjohnwu.superuser.CallbackList import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils import com.topjohnwu.superuser.ShellUtils
@@ -727,14 +730,13 @@ fun applyUmountConfigToKernel(): Boolean {
// 检查 KPM 版本是否可用 // 检查 KPM 版本是否可用
@Composable @Composable
fun rememberKpmAvailable(): Boolean { fun rememberKpmAvailable(): Boolean {
val kpmVersion by produceState(initialValue = "") { var cachedVersion by rememberSaveable { mutableStateOf("") }
value = withContext(Dispatchers.IO) { val kpmVersion by produceState(initialValue = cachedVersion) {
try { val result = withContext(Dispatchers.IO) {
getKpmVersion() runCatching { getKpmVersion() }.getOrElse { "" }
} catch (_: Exception) {
""
}
} }
cachedVersion = result
value = result
} }
return kpmVersion.isNotEmpty() && !kpmVersion.contains("Error", ignoreCase = true) return kpmVersion.isNotEmpty() && !kpmVersion.contains("Error", ignoreCase = true)
} }

View File

@@ -178,9 +178,8 @@
<string name="color_pink">粉色</string> <string name="color_pink">粉色</string>
<string name="color_brown">棕色</string> <string name="color_brown">棕色</string>
<!-- Customize --> <!-- Customize -->
<string name="hook_type">钩子类型</string>
<string name="home_susfs_version">SuSFS 版本</string> <string name="home_susfs_version">SuSFS 版本</string>
<string name="manual_hook">Manual Hook</string>
<string name="inline_hook">Inline Hook</string>
<string name="multi_manager_list">活跃管理器</string> <string name="multi_manager_list">活跃管理器</string>
<string name="default_signature">SukiSU</string> <string name="default_signature">SukiSU</string>
<string name="dynamic_managerature">Dynamic</string> <string name="dynamic_managerature">Dynamic</string>
@@ -320,7 +319,7 @@
<string name="horizon_kernel">AnyKernel3 内核</string> <string name="horizon_kernel">AnyKernel3 内核</string>
<string name="horizon_kernel_summary">刷入AnyKernel3格式的内核zip包</string> <string name="horizon_kernel_summary">刷入AnyKernel3格式的内核zip包</string>
<!-- kpm --> <!-- kpm -->
<string name="kpm_title">KPM</string> <string name="settings_kpm_summary">使用 KPM 管理内核模块</string>
<string name="kpm_empty">当前没有安装内核模块</string> <string name="kpm_empty">当前没有安装内核模块</string>
<string name="kpm_version">版本</string> <string name="kpm_version">版本</string>
<string name="kpm_author">作者</string> <string name="kpm_author">作者</string>

View File

@@ -180,9 +180,11 @@
<string name="color_pink">Pink</string> <string name="color_pink">Pink</string>
<string name="color_brown">Brown</string> <string name="color_brown">Brown</string>
<!-- Customize --> <!-- Customize -->
<string name="home_susfs_version">SuSFS Version</string> <string name="hook_type">Hook Type</string>
<string name="manual_hook">Manual Hook</string> <string name="manual_hook">Manual Hook</string>
<string name="inline_hook">Inline Hook</string> <string name="inline_hook">Inline Hook</string>
<string name="tracepoint_hook">Tracepoint Hook</string>
<string name="home_susfs_version">SuSFS Version</string>
<string name="multi_manager_list">Active Manager</string> <string name="multi_manager_list">Active Manager</string>
<string name="default_signature">SukiSU</string> <string name="default_signature">SukiSU</string>
<string name="dynamic_managerature">Dynamic</string> <string name="dynamic_managerature">Dynamic</string>
@@ -325,6 +327,7 @@
<string name="horizon_kernel_summary">Flash AnyKernel3 format kernel zip</string> <string name="horizon_kernel_summary">Flash AnyKernel3 format kernel zip</string>
<!-- kpm --> <!-- kpm -->
<string name="kpm_title">KPM</string> <string name="kpm_title">KPM</string>
<string name="settings_kpm_summary">Manage kernel modules with KPM</string>
<string name="kpm_empty">No installed kernel modules at this time</string> <string name="kpm_empty">No installed kernel modules at this time</string>
<string name="kpm_version">Version</string> <string name="kpm_version">Version</string>
<string name="kpm_author">Author</string> <string name="kpm_author">Author</string>