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:
@@ -335,11 +335,6 @@ NativeBridge(getUserName, jstring, jint uid) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check if KPM is enabled
|
||||
NativeBridgeNP(isKPMEnabled, jboolean) {
|
||||
return is_KPM_enable();
|
||||
}
|
||||
|
||||
// Get HOOK type
|
||||
NativeBridgeNP(getHookType, jstring) {
|
||||
char hook_type[32] = { 0 };
|
||||
|
||||
@@ -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) {
|
||||
struct ksu_hook_type_cmd cmd = {0};
|
||||
if (ksuctl(KSU_IOCTL_HOOK_TYPE, &cmd) == 0) {
|
||||
|
||||
@@ -229,10 +229,6 @@ struct ksu_hook_type_cmd {
|
||||
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 dynamic_manager_user_config config; // Input/Output: dynamic manager config
|
||||
};
|
||||
|
||||
@@ -88,12 +88,6 @@ bool legacy_is_su_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) {
|
||||
if (hook_type == NULL || size == 0) {
|
||||
return false;
|
||||
|
||||
@@ -121,8 +121,6 @@ object Natives {
|
||||
*/
|
||||
external fun isSuLogEnabled(): Boolean
|
||||
external fun setSuLogEnabled(enabled: Boolean): Boolean
|
||||
|
||||
external fun isKPMEnabled(): Boolean
|
||||
external fun getHookType(): String
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package com.sukisu.ultra.ui
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
@@ -31,6 +30,7 @@ import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import com.ramcosta.composedestinations.DestinationsNavHost
|
||||
@@ -47,13 +47,11 @@ import kotlinx.coroutines.launch
|
||||
import com.sukisu.ultra.Natives
|
||||
import com.sukisu.ultra.ui.component.BottomBar
|
||||
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.SettingPager
|
||||
import com.sukisu.ultra.ui.screen.SuperUserPager
|
||||
import com.sukisu.ultra.ui.theme.KernelSUTheme
|
||||
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.theme.MiuixTheme
|
||||
|
||||
@@ -94,6 +92,7 @@ class MainActivity : ComponentActivity() {
|
||||
android.graphics.Color.TRANSPARENT
|
||||
) { darkMode },
|
||||
)
|
||||
|
||||
val listener = SharedPreferences.OnSharedPreferenceChangeListener { _, key ->
|
||||
when (key) {
|
||||
"color_mode" -> colorMode = prefs.getInt("color_mode", 0)
|
||||
@@ -161,11 +160,7 @@ val LocalHandlePageChange = compositionLocalOf<(Int) -> Unit> { error("No handle
|
||||
fun MainScreen(navController: DestinationsNavigator) {
|
||||
val activity = LocalActivity.current
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
val isKpmAvailable = rememberKpmAvailable()
|
||||
val pageCount = if (isKpmAvailable) 5 else 4
|
||||
|
||||
val pagerState = rememberPagerState(initialPage = 0, pageCount = { pageCount })
|
||||
val pagerState = rememberPagerState(initialPage = 0, pageCount = { 4 })
|
||||
val hazeState = remember { HazeState() }
|
||||
val hazeStyle = HazeStyle(
|
||||
backgroundColor = MiuixTheme.colorScheme.background,
|
||||
@@ -193,7 +188,7 @@ fun MainScreen(navController: DestinationsNavigator) {
|
||||
) {
|
||||
Scaffold(
|
||||
bottomBar = {
|
||||
BottomBar(hazeState, hazeStyle, isKpmAvailable)
|
||||
BottomBar(hazeState, hazeStyle)
|
||||
},
|
||||
) { innerPadding ->
|
||||
HorizontalPager(
|
||||
@@ -202,26 +197,13 @@ fun MainScreen(navController: DestinationsNavigator) {
|
||||
beyondViewportPageCount = 2,
|
||||
userScrollEnabled = false
|
||||
) {
|
||||
when {
|
||||
isKpmAvailable -> {
|
||||
when (it) {
|
||||
0 -> HomePager(pagerState, navController, innerPadding.calculateBottomPadding())
|
||||
1 -> KpmScreen(bottomInnerPadding = 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())
|
||||
}
|
||||
}
|
||||
when (it) {
|
||||
0 -> HomePager(pagerState, navController, innerPadding.calculateBottomPadding())
|
||||
1 -> SuperUserPager(navController, innerPadding.calculateBottomPadding())
|
||||
2 -> ModulePager(navController, innerPadding.calculateBottomPadding())
|
||||
3 -> SettingPager(navController, innerPadding.calculateBottomPadding())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package com.sukisu.ultra.ui.component
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
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.Extension
|
||||
import androidx.compose.material.icons.rounded.Security
|
||||
@@ -28,8 +27,7 @@ import top.yukonga.miuix.kmp.basic.NavigationItem
|
||||
@Composable
|
||||
fun BottomBar(
|
||||
hazeState: HazeState,
|
||||
hazeStyle: HazeStyle,
|
||||
isKpmAvailable: Boolean = false
|
||||
hazeStyle: HazeStyle
|
||||
) {
|
||||
val isManager = Natives.isManager
|
||||
val fullFeatured = isManager && !Natives.requireNewKernel() && rootAvailable()
|
||||
@@ -39,24 +37,12 @@ fun BottomBar(
|
||||
|
||||
if (!fullFeatured) return
|
||||
|
||||
val destinations = if (isKpmAvailable) {
|
||||
BottomBarDestination.entries
|
||||
} else {
|
||||
BottomBarDestination.entries.filter { it != BottomBarDestination.KPM }
|
||||
}
|
||||
|
||||
val item = destinations.mapIndexed { index, destination ->
|
||||
val item = BottomBarDestination.entries.mapIndexed { index, destination ->
|
||||
NavigationItem(
|
||||
label = stringResource(destination.label),
|
||||
icon = destination.icon,
|
||||
)
|
||||
}
|
||||
|
||||
val bottomBarIndex = if (!isKpmAvailable) {
|
||||
page.coerceIn(0, item.size - 1)
|
||||
} else {
|
||||
page.coerceIn(0, item.size - 1)
|
||||
}
|
||||
|
||||
NavigationBar(
|
||||
modifier = Modifier
|
||||
@@ -67,10 +53,8 @@ fun BottomBar(
|
||||
},
|
||||
color = Color.Transparent,
|
||||
items = item,
|
||||
selected = bottomBarIndex,
|
||||
onClick = { index ->
|
||||
handlePageChange(index)
|
||||
}
|
||||
selected = page,
|
||||
onClick = handlePageChange
|
||||
)
|
||||
}
|
||||
|
||||
@@ -79,8 +63,7 @@ enum class BottomBarDestination(
|
||||
val icon: ImageVector,
|
||||
) {
|
||||
Home(R.string.home, Icons.Rounded.Cottage),
|
||||
KPM(R.string.kpm_title, Icons.Rounded.Code),
|
||||
SuperUser(R.string.superuser, Icons.Rounded.Security),
|
||||
Module(R.string.module, Icons.Rounded.Extension),
|
||||
Setting(R.string.settings, Icons.Rounded.Settings)
|
||||
}
|
||||
}
|
||||
@@ -37,11 +37,14 @@ import androidx.compose.material.icons.rounded.CheckCircleOutline
|
||||
import androidx.compose.material.icons.rounded.ErrorOutline
|
||||
import androidx.compose.material.icons.rounded.Link
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
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.graphics.Color
|
||||
@@ -149,8 +152,6 @@ fun HomePager(
|
||||
val lkmMode = ksuVersion?.let {
|
||||
if (kernelVersion.isGKI()) Natives.isLkmMode else null
|
||||
}
|
||||
|
||||
val isKpmAvailable = rememberKpmAvailable()
|
||||
|
||||
Column(
|
||||
modifier = Modifier.padding(vertical = 12.dp),
|
||||
@@ -179,12 +180,12 @@ fun HomePager(
|
||||
},
|
||||
onClickSuperuser = {
|
||||
coroutineScope.launch {
|
||||
pagerState.animateScrollToPage(getSuperuserPageIndex(isKpmAvailable))
|
||||
pagerState.animateScrollToPage(1)
|
||||
}
|
||||
},
|
||||
onclickModule = {
|
||||
coroutineScope.launch {
|
||||
pagerState.animateScrollToPage(getModulePageIndex(isKpmAvailable))
|
||||
pagerState.animateScrollToPage(2)
|
||||
}
|
||||
},
|
||||
themeMode = themeMode
|
||||
@@ -609,6 +610,19 @@ fun DonateCard() {
|
||||
private fun InfoCard() {
|
||||
val manualHookText = stringResource(R.string.manual_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
|
||||
fun InfoText(
|
||||
title: String,
|
||||
@@ -632,23 +646,6 @@ private fun InfoCard() {
|
||||
val context = LocalContext.current
|
||||
val uname = Os.uname()
|
||||
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 {
|
||||
Column(
|
||||
@@ -689,27 +686,26 @@ private fun InfoCard() {
|
||||
)
|
||||
}
|
||||
}
|
||||
InfoText(
|
||||
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(),
|
||||
)
|
||||
if (isSusfsSupported) {
|
||||
InfoText(
|
||||
title = stringResource(R.string.home_susfs_version),
|
||||
content = susfsPair.second,
|
||||
bottomPadding = 0.dp
|
||||
content = susfsInfo.detail
|
||||
)
|
||||
} else {
|
||||
InfoText(
|
||||
title = stringResource(R.string.home_selinux_status),
|
||||
content = getSELinuxStatus(),
|
||||
bottomPadding = 0.dp
|
||||
title = stringResource(R.string.hook_type),
|
||||
content = hookTypeLabel
|
||||
)
|
||||
}
|
||||
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)
|
||||
}
|
||||
|
||||
fun getSuperuserPageIndex(isKpmAvailable: Boolean): Int {
|
||||
return if (isKpmAvailable) 2 else 1
|
||||
private enum class SusfsStatus {
|
||||
Idle, Loading, Supported, Unsupported, Error
|
||||
}
|
||||
|
||||
fun getModulePageIndex(isKpmAvailable: Boolean): Int {
|
||||
return if (isKpmAvailable) 3 else 2
|
||||
private data class SusfsInfoState(
|
||||
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
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import androidx.compose.material.icons.rounded.Palette
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Adb
|
||||
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.Delete
|
||||
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.AppProfileTemplateScreenDestination
|
||||
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.ToolsDestination
|
||||
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.rememberLoadingDialog
|
||||
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.Icon
|
||||
import top.yukonga.miuix.kmp.basic.MiuixScrollBehavior
|
||||
@@ -94,6 +97,8 @@ fun SettingPager(
|
||||
tint = HazeTint(colorScheme.surface.copy(0.8f))
|
||||
)
|
||||
|
||||
val isKpmAvailable = rememberKpmAvailable()
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
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 {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
|
||||
@@ -12,7 +12,10 @@ import android.system.Os
|
||||
import android.util.Log
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
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.Shell
|
||||
import com.topjohnwu.superuser.ShellUtils
|
||||
@@ -727,14 +730,13 @@ fun applyUmountConfigToKernel(): Boolean {
|
||||
// 检查 KPM 版本是否可用
|
||||
@Composable
|
||||
fun rememberKpmAvailable(): Boolean {
|
||||
val kpmVersion by produceState(initialValue = "") {
|
||||
value = withContext(Dispatchers.IO) {
|
||||
try {
|
||||
getKpmVersion()
|
||||
} catch (_: Exception) {
|
||||
""
|
||||
}
|
||||
var cachedVersion by rememberSaveable { mutableStateOf("") }
|
||||
val kpmVersion by produceState(initialValue = cachedVersion) {
|
||||
val result = withContext(Dispatchers.IO) {
|
||||
runCatching { getKpmVersion() }.getOrElse { "" }
|
||||
}
|
||||
cachedVersion = result
|
||||
value = result
|
||||
}
|
||||
return kpmVersion.isNotEmpty() && !kpmVersion.contains("Error", ignoreCase = true)
|
||||
}
|
||||
|
||||
@@ -178,9 +178,8 @@
|
||||
<string name="color_pink">粉色</string>
|
||||
<string name="color_brown">棕色</string>
|
||||
<!-- Customize -->
|
||||
<string name="hook_type">钩子类型</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="default_signature">SukiSU</string>
|
||||
<string name="dynamic_managerature">Dynamic</string>
|
||||
@@ -320,7 +319,7 @@
|
||||
<string name="horizon_kernel">AnyKernel3 内核</string>
|
||||
<string name="horizon_kernel_summary">刷入AnyKernel3格式的内核zip包</string>
|
||||
<!-- kpm -->
|
||||
<string name="kpm_title">KPM</string>
|
||||
<string name="settings_kpm_summary">使用 KPM 管理内核模块</string>
|
||||
<string name="kpm_empty">当前没有安装内核模块</string>
|
||||
<string name="kpm_version">版本</string>
|
||||
<string name="kpm_author">作者</string>
|
||||
|
||||
@@ -180,9 +180,11 @@
|
||||
<string name="color_pink">Pink</string>
|
||||
<string name="color_brown">Brown</string>
|
||||
<!-- 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="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="default_signature">SukiSU</string>
|
||||
<string name="dynamic_managerature">Dynamic</string>
|
||||
@@ -325,6 +327,7 @@
|
||||
<string name="horizon_kernel_summary">Flash AnyKernel3 format kernel zip</string>
|
||||
<!-- kpm -->
|
||||
<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_version">Version</string>
|
||||
<string name="kpm_author">Author</string>
|
||||
|
||||
Reference in New Issue
Block a user