diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt
index 55d83faf..d401806c 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Flash.kt
@@ -4,12 +4,8 @@ import android.net.Uri
import android.os.Environment
import android.os.Parcelable
import androidx.activity.compose.BackHandler
-import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.*
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
@@ -33,22 +29,22 @@ import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
+import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.component.KeyEventBlocker
+import com.sukisu.ultra.ui.theme.CardConfig
+import com.sukisu.ultra.ui.util.*
+import com.sukisu.ultra.ui.viewmodel.ModuleViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
-import com.sukisu.ultra.ui.component.KeyEventBlocker
-import com.sukisu.ultra.ui.util.*
-import com.sukisu.ultra.R
-import com.sukisu.ultra.ui.theme.CardConfig
-import com.sukisu.ultra.ui.viewmodel.ModuleViewModel
-import androidx.lifecycle.viewmodel.compose.viewModel
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt
index 0e61f504..2a657d94 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Home.kt
@@ -6,29 +6,11 @@ import android.os.Build
import android.os.PowerManager
import android.system.Os
import androidx.annotation.StringRes
-import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.*
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
@@ -40,29 +22,8 @@ import androidx.compose.material.icons.outlined.TaskAlt
import androidx.compose.material.icons.outlined.Warning
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.DropdownMenu
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.ElevatedCard
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.material3.rememberTopAppBarState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-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.material3.*
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -89,11 +50,11 @@ import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.getCardColors
import com.sukisu.ultra.ui.theme.getCardElevation
+import com.sukisu.ultra.ui.util.SuSFSManager
import com.sukisu.ultra.ui.util.checkNewVersion
+import com.sukisu.ultra.ui.util.getSuSFS
import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import com.sukisu.ultra.ui.util.reboot
-import com.sukisu.ultra.ui.util.getSuSFS
-import com.sukisu.ultra.ui.util.SuSFSManager
import com.sukisu.ultra.ui.viewmodel.HomeViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -366,7 +327,7 @@ private fun StatusCard(
systemStatus.ksuVersion != null -> {
val workingModeText = when {
- Natives.isSafeMode == true -> stringResource(id = R.string.safe_mode)
+ Natives.isSafeMode -> stringResource(id = R.string.safe_mode)
else -> stringResource(id = R.string.home_working)
}
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt
index cc54ae3b..a0a910e1 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Install.kt
@@ -7,22 +7,11 @@ import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.StringRes
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
+import androidx.compose.animation.*
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.verticalScroll
@@ -30,31 +19,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.AutoFixHigh
import androidx.compose.material.icons.filled.FileUpload
-import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ElevatedCard
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.ListItem
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.RadioButton
-import androidx.compose.material3.RadioButtonDefaults
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.material3.rememberTopAppBarState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.produceState
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -78,22 +44,17 @@ import com.ramcosta.composedestinations.generated.destinations.KernelFlashScreen
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
import com.sukisu.ultra.R
+import com.sukisu.ultra.getKernelVersion
import com.sukisu.ultra.ui.component.DialogHandle
import com.sukisu.ultra.ui.component.SlotSelectionDialog
import com.sukisu.ultra.ui.component.rememberConfirmDialog
import com.sukisu.ultra.ui.component.rememberCustomDialog
+import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.getCardColors
-import com.sukisu.ultra.ui.util.LkmSelection
-import com.sukisu.ultra.ui.util.getCurrentKmi
-import com.sukisu.ultra.ui.util.getSupportedKmis
-import com.sukisu.ultra.ui.util.isAbDevice
-import com.sukisu.ultra.ui.util.isInitBoot
-import com.sukisu.ultra.ui.util.rootAvailable
-import com.sukisu.ultra.getKernelVersion
-import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.getCardElevation
+import com.sukisu.ultra.ui.util.*
/**
* @author ShirkNeko
@@ -413,9 +374,9 @@ private fun SelectInstallMethod(
else -> null
}
- option?.let { it ->
- selectedOption = it
- onSelected(it)
+ option?.let { opt ->
+ selectedOption = opt
+ onSelected(opt)
}
}
}
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt
index 6f36c672..6f343176 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Kpm.kt
@@ -1,5 +1,6 @@
package com.sukisu.ultra.ui.screen
+import android.app.Activity
import android.content.Context
import android.content.Intent
import android.util.Log
@@ -17,25 +18,27 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
+import androidx.core.content.edit
import androidx.lifecycle.viewmodel.compose.viewModel
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
+import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.component.*
+import com.sukisu.ultra.ui.theme.getCardColors
+import com.sukisu.ultra.ui.theme.getCardElevation
+import com.sukisu.ultra.ui.util.loadKpmModule
+import com.sukisu.ultra.ui.util.unloadKpmModule
+import com.sukisu.ultra.ui.viewmodel.KpmViewModel
+import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
-import com.sukisu.ultra.ui.component.*
-import com.sukisu.ultra.ui.theme.*
-import com.sukisu.ultra.ui.viewmodel.KpmViewModel
-import com.sukisu.ultra.ui.util.*
import java.io.File
-import androidx.core.content.edit
-import com.sukisu.ultra.R
import java.io.FileInputStream
-import java.net.*
-import android.app.Activity
-import androidx.compose.ui.res.painterResource
+import java.net.URLEncoder
/**
* KPM 管理界面
@@ -83,9 +86,8 @@ fun KpmScreen(
LaunchedEffect(tempFileForInstall) {
tempFileForInstall?.let { tempFile ->
try {
- val shell = getRootShell()
val command = "strings ${tempFile.absolutePath} | grep 'name='"
- val result = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val result = Shell.cmd(command).to(ArrayList(), null).exec()
if (result.isSuccess) {
for (line in result.out) {
if (line.startsWith("name=")) {
@@ -424,9 +426,8 @@ private suspend fun handleModuleInstall(
) {
var moduleId: String? = null
try {
- val shell = getRootShell()
val command = "strings ${tempFile.absolutePath} | grep 'name='"
- val result = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val result = Shell.cmd(command).to(ArrayList(), null).exec()
if (result.isSuccess) {
for (line in result.out) {
if (line.startsWith("name=")) {
@@ -453,9 +454,8 @@ private suspend fun handleModuleInstall(
try {
if (isEmbed) {
- val shell = getRootShell()
- shell.newJob().add("mkdir -p /data/adb/kpm").exec()
- shell.newJob().add("cp ${tempFile.absolutePath} $targetPath").exec()
+ Shell.cmd("mkdir -p /data/adb/kpm").exec()
+ Shell.cmd("cp ${tempFile.absolutePath} $targetPath").exec()
}
val loadResult = loadKpmModule(tempFile.absolutePath)
@@ -499,8 +499,7 @@ private suspend fun handleModuleUninstall(
val moduleFilePath = "/data/adb/kpm/$moduleFileName"
val fileExists = try {
- val shell = getRootShell()
- val result = shell.newJob().add("ls /data/adb/kpm/$moduleFileName").exec()
+ val result = Shell.cmd("ls /data/adb/kpm/$moduleFileName").exec()
result.isSuccess
} catch (e: Exception) {
Log.e("KsuCli", "Failed to check module file existence: ${e.message}", e)
@@ -531,8 +530,7 @@ private suspend fun handleModuleUninstall(
}
if (fileExists) {
- val shell = getRootShell()
- shell.newJob().add("rm $moduleFilePath").exec()
+ Shell.cmd("rm $moduleFilePath").exec()
}
viewModel.fetchModuleList()
@@ -703,9 +701,8 @@ private fun KpmModuleItem(
}
private fun checkStringsCommand(tempFile: File): Int {
- val shell = getRootShell()
val command = "strings ${tempFile.absolutePath} | grep -E 'name=|version=|license=|author='"
- val result = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val result = Shell.cmd(command).to(ArrayList(), null).exec()
if (!result.isSuccess) {
return 0
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt
index 8aa1f0a8..3f4ceadf 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Module.kt
@@ -11,9 +11,12 @@ import android.util.Log
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.animation.*
-import androidx.compose.animation.core.*
-import androidx.compose.foundation.*
+import androidx.compose.animation.core.Spring
+import androidx.compose.animation.core.animateFloatAsState
+import androidx.compose.animation.core.spring
+import androidx.compose.foundation.LocalIndication
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
import androidx.compose.foundation.layout.*
@@ -28,8 +31,9 @@ import androidx.compose.foundation.selection.toggleable
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.outlined.*
-import androidx.compose.material.icons.filled.*
+import androidx.compose.material.icons.automirrored.outlined.Wysiwyg
+import androidx.compose.material.icons.filled.MoreVert
+import androidx.compose.material.icons.filled.Verified
import androidx.compose.material.icons.outlined.*
import androidx.compose.material3.*
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
@@ -41,7 +45,8 @@ import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.input.nestedscroll.nestedScroll
-import androidx.compose.ui.platform.*
+import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.Role
@@ -52,45 +57,32 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
+import androidx.core.content.edit
+import androidx.core.net.toUri
import androidx.lifecycle.viewmodel.compose.viewModel
+import com.dergoogler.mmrl.platform.Platform
+import com.dergoogler.mmrl.platform.model.ModuleConfig
+import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.navigation.EmptyDestinationsNavigator
+import com.sukisu.ultra.Natives
+import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.component.*
+import com.sukisu.ultra.ui.theme.getCardColors
+import com.sukisu.ultra.ui.theme.getCardElevation
+import com.sukisu.ultra.ui.util.*
+import com.sukisu.ultra.ui.viewmodel.ModuleViewModel
+import com.sukisu.ultra.ui.webui.WebUIActivity
+import com.sukisu.ultra.ui.webui.WebUIXActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import com.sukisu.ultra.Natives
-import com.sukisu.ultra.ui.component.ConfirmResult
-import com.sukisu.ultra.ui.component.SearchAppBar
-import com.sukisu.ultra.ui.component.rememberConfirmDialog
-import com.sukisu.ultra.ui.component.rememberLoadingDialog
-import com.sukisu.ultra.ui.util.DownloadListener
-import com.sukisu.ultra.ui.util.*
-import com.sukisu.ultra.ui.util.download
-import com.sukisu.ultra.ui.util.hasMagisk
-import com.sukisu.ultra.ui.util.reboot
-import com.sukisu.ultra.ui.util.restoreModule
-import com.sukisu.ultra.ui.util.toggleModule
-import com.sukisu.ultra.ui.util.uninstallModule
-import com.sukisu.ultra.ui.webui.WebUIActivity
import okhttp3.OkHttpClient
-import com.sukisu.ultra.ui.util.ModuleModify
-import com.sukisu.ultra.ui.theme.getCardColors
-import com.sukisu.ultra.ui.viewmodel.ModuleViewModel
import java.util.concurrent.TimeUnit
-import androidx.core.content.edit
-import com.sukisu.ultra.R
-import com.sukisu.ultra.ui.webui.WebUIXActivity
-import com.dergoogler.mmrl.platform.Platform
-import androidx.core.net.toUri
-import com.dergoogler.mmrl.platform.model.ModuleConfig
-import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig
-import com.sukisu.ultra.ui.component.AnimatedFab
-import com.sukisu.ultra.ui.component.rememberFabVisibilityState
-import com.sukisu.ultra.ui.theme.getCardElevation
// 菜单项数据类
data class ModuleBottomSheetMenuItem(
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt
index d0484fef..7f6314ef 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Settings.kt
@@ -6,11 +6,7 @@ import android.net.Uri
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
+import androidx.compose.animation.*
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.*
@@ -21,13 +17,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.Undo
import androidx.compose.material.icons.filled.*
import androidx.compose.material3.*
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -47,20 +38,21 @@ import com.ramcosta.composedestinations.generated.destinations.AppProfileTemplat
import com.ramcosta.composedestinations.generated.destinations.FlashScreenDestination
import com.ramcosta.composedestinations.generated.destinations.MoreSettingsScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.withContext
import com.sukisu.ultra.BuildConfig
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.component.*
-import com.sukisu.ultra.ui.theme.*
+import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
+import com.sukisu.ultra.ui.theme.getCardColors
+import com.sukisu.ultra.ui.theme.getCardElevation
import com.sukisu.ultra.ui.util.LocalSnackbarHost
import com.sukisu.ultra.ui.util.getBugreportFile
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
-import com.sukisu.ultra.ui.component.KsuIsValid
/**
* @author ShirkNeko
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt
index 68419044..583207b2 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuSFSConfig.kt
@@ -3,58 +3,15 @@ package com.sukisu.ultra.ui.screen
import android.annotation.SuppressLint
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.*
-import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.Button
-import androidx.compose.material3.Card
-import androidx.compose.material3.CardDefaults
-import androidx.compose.material3.CenterAlignedTopAppBar
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExposedDropdownMenuBox
-import androidx.compose.material3.ExposedDropdownMenuDefaults
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.MenuAnchorType
-import androidx.compose.material3.OutlinedButton
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.ScrollableTabRow
-import androidx.compose.material3.Surface
-import androidx.compose.material3.Switch
-import androidx.compose.material3.Tab
-import androidx.compose.material3.Text
-import androidx.compose.material3.TextButton
-import androidx.compose.material3.TopAppBarDefaults
-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.material3.*
+import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
@@ -68,18 +25,7 @@ import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.sukisu.ultra.R
-import com.sukisu.ultra.ui.component.AddAppPathDialog
-import com.sukisu.ultra.ui.component.AddKstatStaticallyDialog
-import com.sukisu.ultra.ui.component.AddPathDialog
-import com.sukisu.ultra.ui.component.AddTryUmountDialog
-import com.sukisu.ultra.ui.component.ConfirmDialog
-import com.sukisu.ultra.ui.component.EnabledFeaturesContent
-import com.sukisu.ultra.ui.component.KstatConfigContent
-import com.sukisu.ultra.ui.component.PathSettingsContent
-import com.sukisu.ultra.ui.component.SusMountsContent
-import com.sukisu.ultra.ui.component.SusPathsContent
-import com.sukisu.ultra.ui.component.SusLoopPathsContent
-import com.sukisu.ultra.ui.component.TryUmountContent
+import com.sukisu.ultra.ui.component.*
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.util.SuSFSManager
import com.sukisu.ultra.ui.util.SuSFSManager.isSusVersion158
@@ -1171,7 +1117,7 @@ fun SuSFSConfigScreen(
containerColor = MaterialTheme.colorScheme.surface,
contentColor = MaterialTheme.colorScheme.onSurface
) {
- allTabs.forEachIndexed { index, tab ->
+ allTabs.forEach { tab ->
Tab(
selected = selectedTab == tab,
onClick = { selectedTab = tab },
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
index fad39069..e2434b74 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/SuperUser.kt
@@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import androidx.compose.animation.*
import androidx.compose.animation.core.*
import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
@@ -17,7 +18,6 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.clickable
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
@@ -34,31 +34,30 @@ import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
-import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.lifecycle.viewmodel.compose.viewModel
-import com.sukisu.ultra.R
import coil.compose.AsyncImage
import coil.request.ImageRequest
+import com.dergoogler.mmrl.ui.component.LabelItem
+import com.dergoogler.mmrl.ui.component.LabelItemDefaults
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.generated.destinations.AppProfileScreenDestination
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
-import kotlinx.coroutines.launch
import com.sukisu.ultra.Natives
+import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.component.FabMenuPresets
import com.sukisu.ultra.ui.component.SearchAppBar
import com.sukisu.ultra.ui.component.VerticalExpandableFab
-import com.sukisu.ultra.ui.component.FabMenuPresets
import com.sukisu.ultra.ui.util.ModuleModify
-import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.sukisu.ultra.ui.viewmodel.AppCategory
import com.sukisu.ultra.ui.viewmodel.SortType
-import com.dergoogler.mmrl.ui.component.LabelItem
-import com.dergoogler.mmrl.ui.component.LabelItemDefaults
-import kotlin.math.*
+import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
+import kotlinx.coroutines.launch
import java.io.File
// 应用优先级枚举
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt
index ac07fc6c..41eb32ff 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/Template.kt
@@ -4,16 +4,7 @@ import android.content.ClipData
import android.content.ClipboardManager
import android.widget.Toast
import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.ExperimentalLayoutApi
-import androidx.compose.foundation.layout.FlowRow
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.ExperimentalMaterialApi
@@ -22,28 +13,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.ImportExport
import androidx.compose.material.icons.filled.Sync
-import androidx.compose.material3.DropdownMenu
-import androidx.compose.material3.DropdownMenuItem
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.ExtendedFloatingActionButton
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.ListItem
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
+import androidx.compose.material3.*
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
-import androidx.compose.material3.rememberTopAppBarState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-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.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
@@ -58,11 +30,11 @@ import com.ramcosta.composedestinations.generated.destinations.TemplateEditorScr
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.ramcosta.composedestinations.result.ResultRecipient
import com.ramcosta.composedestinations.result.getOr
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
import com.sukisu.ultra.R
import com.sukisu.ultra.ui.theme.CardConfig
import com.sukisu.ultra.ui.viewmodel.TemplateViewModel
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
/**
* @author weishu
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt
index d00ad186..89e3e7b4 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/screen/TemplateEditor.kt
@@ -2,13 +2,7 @@ package com.sukisu.ultra.ui.screen
import android.widget.Toast
import androidx.activity.compose.BackHandler
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.safeDrawing
+import androidx.compose.foundation.layout.*
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
@@ -17,24 +11,9 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.DeleteForever
import androidx.compose.material.icons.filled.Save
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.ListItem
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.TopAppBarScrollBehavior
-import androidx.compose.material3.rememberTopAppBarState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.runtime.setValue
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -44,6 +23,7 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
+import androidx.lifecycle.compose.dropUnlessResumed
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.result.ResultBackNavigator
@@ -55,7 +35,6 @@ import com.sukisu.ultra.ui.util.getAppProfileTemplate
import com.sukisu.ultra.ui.util.setAppProfileTemplate
import com.sukisu.ultra.ui.viewmodel.TemplateViewModel
import com.sukisu.ultra.ui.viewmodel.toJSON
-import androidx.lifecycle.compose.dropUnlessResumed
/**
* @author weishu
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt
index 806ccc4f..e05ce3ba 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/CardManage.kt
@@ -3,11 +3,7 @@ package com.sukisu.ultra.ui.theme
import android.content.Context
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.material3.CardDefaults
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.*
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
import androidx.compose.ui.unit.dp
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt
index f7e02669..ad8cb631 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/theme/Theme.kt
@@ -5,51 +5,40 @@ import android.content.Context
import android.net.Uri
import android.os.Build
import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.activity.SystemBarStyle
+import androidx.activity.enableEdgeToEdge
import androidx.annotation.RequiresApi
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.updateTransition
+import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.darkColorScheme
-import androidx.compose.material3.dynamicDarkColorScheme
-import androidx.compose.material3.dynamicLightColorScheme
-import androidx.compose.material3.lightColorScheme
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
+import androidx.compose.material3.*
+import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.paint
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.unit.dp
import androidx.compose.ui.zIndex
+import androidx.core.content.edit
+import androidx.core.net.toUri
import coil.compose.AsyncImagePainter
import coil.compose.rememberAsyncImagePainter
-import androidx.compose.foundation.background
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.unit.dp
+import com.sukisu.ultra.ui.util.BackgroundTransformation
+import com.sukisu.ultra.ui.util.saveTransformedBackground
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
-import androidx.core.content.edit
-import androidx.core.net.toUri
-import com.sukisu.ultra.ui.util.BackgroundTransformation
-import com.sukisu.ultra.ui.util.saveTransformedBackground
-import androidx.activity.SystemBarStyle
-import androidx.activity.ComponentActivity
-import androidx.activity.enableEdgeToEdge
-import androidx.compose.material3.ColorScheme
-import androidx.compose.runtime.SideEffect
-import androidx.compose.ui.graphics.toArgb
/**
* 主题配置对象,管理应用的主题相关状态
@@ -166,8 +155,8 @@ fun KernelSUTheme(
val bgImagePainter = backgroundUri.value?.let {
rememberAsyncImagePainter(
model = it,
- onError = {
- Log.e("ThemeSystem", "背景图加载失败: ${it.result.throwable.message}")
+ onError = { err ->
+ Log.e("ThemeSystem", "背景图加载失败: ${err.result.throwable.message}")
ThemeConfig.customBackgroundUri = null
context.saveCustomBackground(null)
},
@@ -222,7 +211,7 @@ fun KernelSUTheme(
)
// 自定义背景层
- backgroundUri.value?.let { uri ->
+ backgroundUri.value?.let {
Box(
modifier = Modifier
.fillMaxSize()
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt
index 498d49d4..1f662214 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/BackgroundUtils.kt
@@ -8,10 +8,10 @@ import android.graphics.Canvas
import android.graphics.Matrix
import android.net.Uri
import android.util.Log
+import androidx.core.graphics.createBitmap
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
-import androidx.core.graphics.createBitmap
data class BackgroundTransformation(
val scale: Float = 1f,
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt
index af7a314a..035137fd 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/Downloader.kt
@@ -15,8 +15,8 @@ import android.util.Log
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.core.content.ContextCompat
-import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import androidx.core.net.toUri
+import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import java.io.File
import java.util.concurrent.TimeUnit
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java
index b7104115..fe1ebe69 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HanziToPinyin.java
@@ -32,7 +32,8 @@ import java.util.Locale;
*
* Currently this file is aligned to zh.txt in ICU 4.6
*/
-public class HanziToPinyin {
+@SuppressWarnings("SizeReplaceableByIsEmpty")
+public record HanziToPinyin(boolean mHasChinaCollator) {
private static final String TAG = "HanziToPinyin";
// Turn on this flag when we want to check internal data structure.
@@ -44,77 +45,77 @@ public class HanziToPinyin {
* Each unihans is the first one within same pinyin when collator is zh_CN.
*/
public static final char[] UNIHANS = {
- '\u963f', '\u54ce', '\u5b89', '\u80ae', '\u51f9', '\u516b',
- '\u6300', '\u6273', '\u90a6', '\u52f9', '\u9642', '\u5954',
- '\u4f3b', '\u5c44', '\u8fb9', '\u706c', '\u618b', '\u6c43',
- '\u51ab', '\u7676', '\u5cec', '\u5693', '\u5072', '\u53c2',
- '\u4ed3', '\u64a1', '\u518a', '\u5d7e', '\u66fd', '\u66fe',
- '\u5c64', '\u53c9', '\u8286', '\u8fbf', '\u4f25', '\u6284',
- '\u8f66', '\u62bb', '\u6c88', '\u6c89', '\u9637', '\u5403',
- '\u5145', '\u62bd', '\u51fa', '\u6b3b', '\u63e3', '\u5ddb',
- '\u5205', '\u5439', '\u65fe', '\u9034', '\u5472', '\u5306',
- '\u51d1', '\u7c97', '\u6c46', '\u5d14', '\u90a8', '\u6413',
- '\u5491', '\u5446', '\u4e39', '\u5f53', '\u5200', '\u561a',
- '\u6265', '\u706f', '\u6c10', '\u55f2', '\u7538', '\u5201',
- '\u7239', '\u4e01', '\u4e1f', '\u4e1c', '\u543a', '\u53be',
- '\u8011', '\u8968', '\u5428', '\u591a', '\u59b8', '\u8bf6',
- '\u5940', '\u97a5', '\u513f', '\u53d1', '\u5e06', '\u531a',
- '\u98de', '\u5206', '\u4e30', '\u8985', '\u4ecf', '\u7d11',
- '\u4f15', '\u65ee', '\u4f85', '\u7518', '\u5188', '\u768b',
- '\u6208', '\u7ed9', '\u6839', '\u522f', '\u5de5', '\u52fe',
- '\u4f30', '\u74dc', '\u4e56', '\u5173', '\u5149', '\u5f52',
- '\u4e28', '\u5459', '\u54c8', '\u548d', '\u4f44', '\u592f',
- '\u8320', '\u8bc3', '\u9ed2', '\u62eb', '\u4ea8', '\u5677',
- '\u53ff', '\u9f41', '\u4e6f', '\u82b1', '\u6000', '\u72bf',
- '\u5ddf', '\u7070', '\u660f', '\u5419', '\u4e0c', '\u52a0',
- '\u620b', '\u6c5f', '\u827d', '\u9636', '\u5dfe', '\u5755',
- '\u5182', '\u4e29', '\u51e5', '\u59e2', '\u5658', '\u519b',
- '\u5494', '\u5f00', '\u520a', '\u5ffc', '\u5c3b', '\u533c',
- '\u808e', '\u52a5', '\u7a7a', '\u62a0', '\u625d', '\u5938',
- '\u84af', '\u5bbd', '\u5321', '\u4e8f', '\u5764', '\u6269',
- '\u5783', '\u6765', '\u5170', '\u5577', '\u635e', '\u808b',
- '\u52d2', '\u5d1a', '\u5215', '\u4fe9', '\u5941', '\u826f',
- '\u64a9', '\u5217', '\u62ce', '\u5222', '\u6e9c', '\u56d6',
- '\u9f99', '\u779c', '\u565c', '\u5a08', '\u7567', '\u62a1',
- '\u7f57', '\u5463', '\u5988', '\u57cb', '\u5ada', '\u7264',
- '\u732b', '\u4e48', '\u5445', '\u95e8', '\u753f', '\u54aa',
- '\u5b80', '\u55b5', '\u4e5c', '\u6c11', '\u540d', '\u8c2c',
- '\u6478', '\u54de', '\u6bea', '\u55ef', '\u62cf', '\u8149',
- '\u56e1', '\u56d4', '\u5b6c', '\u7592', '\u5a1e', '\u6041',
- '\u80fd', '\u59ae', '\u62c8', '\u5b22', '\u9e1f', '\u634f',
- '\u56dc', '\u5b81', '\u599e', '\u519c', '\u7fba', '\u5974',
- '\u597b', '\u759f', '\u9ec1', '\u90cd', '\u5594', '\u8bb4',
- '\u5991', '\u62cd', '\u7705', '\u4e53', '\u629b', '\u5478',
- '\u55b7', '\u5309', '\u4e15', '\u56e8', '\u527d', '\u6c15',
- '\u59d8', '\u4e52', '\u948b', '\u5256', '\u4ec6', '\u4e03',
- '\u6390', '\u5343', '\u545b', '\u6084', '\u767f', '\u4eb2',
- '\u72c5', '\u828e', '\u4e18', '\u533a', '\u5cd1', '\u7f3a',
- '\u590b', '\u5465', '\u7a63', '\u5a06', '\u60f9', '\u4eba',
- '\u6254', '\u65e5', '\u8338', '\u53b9', '\u909a', '\u633c',
- '\u5827', '\u5a51', '\u77a4', '\u637c', '\u4ee8', '\u6be2',
- '\u4e09', '\u6852', '\u63bb', '\u95aa', '\u68ee', '\u50e7',
- '\u6740', '\u7b5b', '\u5c71', '\u4f24', '\u5f30', '\u5962',
- '\u7533', '\u8398', '\u6552', '\u5347', '\u5c38', '\u53ce',
- '\u4e66', '\u5237', '\u8870', '\u95e9', '\u53cc', '\u8c01',
- '\u542e', '\u8bf4', '\u53b6', '\u5fea', '\u635c', '\u82cf',
- '\u72fb', '\u590a', '\u5b59', '\u5506', '\u4ed6', '\u56fc',
- '\u574d', '\u6c64', '\u5932', '\u5fd1', '\u71a5', '\u5254',
- '\u5929', '\u65eb', '\u5e16', '\u5385', '\u56f2', '\u5077',
- '\u51f8', '\u6e4d', '\u63a8', '\u541e', '\u4e47', '\u7a75',
- '\u6b6a', '\u5f2f', '\u5c23', '\u5371', '\u6637', '\u7fc1',
- '\u631d', '\u4e4c', '\u5915', '\u8672', '\u4eda', '\u4e61',
- '\u7071', '\u4e9b', '\u5fc3', '\u661f', '\u51f6', '\u4f11',
- '\u5401', '\u5405', '\u524a', '\u5743', '\u4e2b', '\u6079',
- '\u592e', '\u5e7a', '\u503b', '\u4e00', '\u56d9', '\u5e94',
- '\u54df', '\u4f63', '\u4f18', '\u625c', '\u56e6', '\u66f0',
- '\u6655', '\u7b60', '\u7b7c', '\u5e00', '\u707d', '\u5142',
- '\u5328', '\u50ae', '\u5219', '\u8d3c', '\u600e', '\u5897',
- '\u624e', '\u635a', '\u6cbe', '\u5f20', '\u957f', '\u9577',
- '\u4f4b', '\u8707', '\u8d1e', '\u4e89', '\u4e4b', '\u5cd9',
- '\u5ea2', '\u4e2d', '\u5dde', '\u6731', '\u6293', '\u62fd',
- '\u4e13', '\u5986', '\u96b9', '\u5b92', '\u5353', '\u4e72',
- '\u5b97', '\u90b9', '\u79df', '\u94bb', '\u539c', '\u5c0a',
- '\u6628', '\u5159', '\u9fc3', '\u9fc4',};
+ '阿', '哎', '安', '肮', '凹', '八',
+ '挀', '扳', '邦', '勹', '陂', '奔',
+ '伻', '屄', '边', '灬', '憋', '汃',
+ '冫', '癶', '峬', '嚓', '偲', '参',
+ '仓', '撡', '冊', '嵾', '曽', '曾',
+ '層', '叉', '芆', '辿', '伥', '抄',
+ '车', '抻', '沈', '沉', '阷', '吃',
+ '充', '抽', '出', '欻', '揣', '巛',
+ '刅', '吹', '旾', '逴', '呲', '匆',
+ '凑', '粗', '汆', '崔', '邨', '搓',
+ '咑', '呆', '丹', '当', '刀', '嘚',
+ '扥', '灯', '氐', '嗲', '甸', '刁',
+ '爹', '丁', '丟', '东', '吺', '厾',
+ '耑', '襨', '吨', '多', '妸', '诶',
+ '奀', '鞥', '儿', '发', '帆', '匚',
+ '飞', '分', '丰', '覅', '仏', '紑',
+ '伕', '旮', '侅', '甘', '冈', '皋',
+ '戈', '给', '根', '刯', '工', '勾',
+ '估', '瓜', '乖', '关', '光', '归',
+ '丨', '呙', '哈', '咍', '佄', '夯',
+ '茠', '诃', '黒', '拫', '亨', '噷',
+ '叿', '齁', '乯', '花', '怀', '犿',
+ '巟', '灰', '昏', '吙', '丌', '加',
+ '戋', '江', '艽', '阶', '巾', '坕',
+ '冂', '丩', '凥', '姢', '噘', '军',
+ '咔', '开', '刊', '忼', '尻', '匼',
+ '肎', '劥', '空', '抠', '扝', '夸',
+ '蒯', '宽', '匡', '亏', '坤', '扩',
+ '垃', '来', '兰', '啷', '捞', '肋',
+ '勒', '崚', '刕', '俩', '奁', '良',
+ '撩', '列', '拎', '刢', '溜', '囖',
+ '龙', '瞜', '噜', '娈', '畧', '抡',
+ '罗', '呣', '妈', '埋', '嫚', '牤',
+ '猫', '么', '呅', '门', '甿', '咪',
+ '宀', '喵', '乜', '民', '名', '谬',
+ '摸', '哞', '毪', '嗯', '拏', '腉',
+ '囡', '囔', '孬', '疒', '娞', '恁',
+ '能', '妮', '拈', '嬢', '鸟', '捏',
+ '囜', '宁', '妞', '农', '羺', '奴',
+ '奻', '疟', '黁', '郍', '喔', '讴',
+ '妑', '拍', '眅', '乓', '抛', '呸',
+ '喷', '匉', '丕', '囨', '剽', '氕',
+ '姘', '乒', '钋', '剖', '仆', '七',
+ '掐', '千', '呛', '悄', '癿', '亲',
+ '狅', '芎', '丘', '区', '峑', '缺',
+ '夋', '呥', '穣', '娆', '惹', '人',
+ '扔', '日', '茸', '厹', '邚', '挼',
+ '堧', '婑', '瞤', '捼', '仨', '毢',
+ '三', '桒', '掻', '閪', '森', '僧',
+ '杀', '筛', '山', '伤', '弰', '奢',
+ '申', '莘', '敒', '升', '尸', '収',
+ '书', '刷', '衰', '闩', '双', '谁',
+ '吮', '说', '厶', '忪', '捜', '苏',
+ '狻', '夊', '孙', '唆', '他', '囼',
+ '坍', '汤', '夲', '忑', '熥', '剔',
+ '天', '旫', '帖', '厅', '囲', '偷',
+ '凸', '湍', '推', '吞', '乇', '穵',
+ '歪', '弯', '尣', '危', '昷', '翁',
+ '挝', '乌', '夕', '虲', '仚', '乡',
+ '灱', '些', '心', '星', '凶', '休',
+ '吁', '吅', '削', '坃', '丫', '恹',
+ '央', '幺', '倻', '一', '囙', '应',
+ '哟', '佣', '优', '扜', '囦', '曰',
+ '晕', '筠', '筼', '帀', '災', '兂',
+ '匨', '傮', '则', '贼', '怎', '増',
+ '扎', '捚', '沾', '张', '长', '長',
+ '佋', '蜇', '贞', '争', '之', '峙',
+ '庢', '中', '州', '朱', '抓', '拽',
+ '专', '妆', '隹', '宒', '卓', '乲',
+ '宗', '邹', '租', '钻', '厜', '尊',
+ '昨', '兙', '鿃', '鿄'};
/**
* Pinyin array.
@@ -334,18 +335,17 @@ public class HanziToPinyin {
{90, 85, 0, 0, 0, 0}, {90, 85, 65, 78, 0, 0},
{90, 85, 73, 0, 0, 0}, {90, 85, 78, 0, 0, 0},
{90, 85, 79, 0, 0, 0}, {0, 0, 0, 0, 0, 0},
- {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0},};
+ {83, 72, 65, 78, 0, 0}, {0, 0, 0, 0, 0, 0}};
/**
* First and last Chinese character with known Pinyin according to zh collation
*/
- private static final String FIRST_PINYIN_UNIHAN = "\u963F";
- private static final String LAST_PINYIN_UNIHAN = "\u9FFF";
+ private static final String FIRST_PINYIN_UNIHAN = "阿";
+ private static final String LAST_PINYIN_UNIHAN = "鿿";
private static final Collator COLLATOR = Collator.getInstance(Locale.CHINA);
private static HanziToPinyin sInstance;
- private final boolean mHasChinaCollator;
public static class Token {
/**
@@ -381,10 +381,6 @@ public class HanziToPinyin {
public String target;
}
- protected HanziToPinyin(boolean hasChinaCollator) {
- mHasChinaCollator = hasChinaCollator;
- }
-
public static HanziToPinyin getInstance() {
synchronized (HanziToPinyin.class) {
if (sInstance != null) {
@@ -402,8 +398,8 @@ public class HanziToPinyin {
return sInstance;
}
}
- if (sInstance == null){//这个判断是用于处理国产ROM的兼容性问题
- if (Locale.CHINA.equals(Locale.getDefault())){
+ if (sInstance == null) {//这个判断是用于处理国产ROM的兼容性问题
+ if (Locale.CHINA.equals(Locale.getDefault())) {
sInstance = new HanziToPinyin(true);
return sInstance;
}
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt
index bdd9b6fb..36ea19c3 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/HyperlinkText.kt
@@ -76,6 +76,7 @@ private data class LinkInfo(
val end: Int
)
+@Suppress("HttpUrlsUsage")
private fun extractUrls(text: String): List = buildList {
val matcher = urlPattern.matcher(text)
while (matcher.find()) {
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt
index 16c90b68..f12c06dd 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/KsuCli.kt
@@ -10,15 +10,15 @@ import android.os.SystemClock
import android.provider.OpenableColumns
import android.system.Os
import android.util.Log
+import com.sukisu.ultra.Natives
+import com.sukisu.ultra.ksuApp
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.Shell
import com.topjohnwu.superuser.ShellUtils
+import com.topjohnwu.superuser.io.SuFile
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.parcelize.Parcelize
-import com.sukisu.ultra.BuildConfig
-import com.sukisu.ultra.Natives
-import com.sukisu.ultra.ksuApp
import org.json.JSONArray
import java.io.File
@@ -29,19 +29,8 @@ import java.io.File
*/
private const val TAG = "KsuCli"
-private fun getKsuDaemonPath(): String {
- return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libzakozako.so"
-}
-
-object KsuCli {
- val SHELL: Shell = createRootShell()
- val GLOBAL_MNT_SHELL: Shell = createRootShell(true)
-}
-
-fun getRootShell(globalMnt: Boolean = false): Shell {
- return if (globalMnt) KsuCli.GLOBAL_MNT_SHELL else {
- KsuCli.SHELL
- }
+private val ksuDaemonPath by lazy {
+ "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libzakozako.so"
}
inline fun withNewRootShell(
@@ -63,37 +52,39 @@ fun Uri.getFileName(context: Context): String? {
return fileName
}
+fun createRootShellBuilder(globalMnt: Boolean = false): Shell.Builder {
+ return Shell.Builder.create().run {
+ val cmd = buildString {
+ append("$ksuDaemonPath debug su")
+ if (globalMnt) append(" -g")
+ append(" || ")
+ append("su")
+ if (globalMnt) append(" --mount-master")
+ append(" || ")
+ append("sh")
+ }
+ setCommands("sh", "-c", cmd)
+ }
+}
+
fun createRootShell(globalMnt: Boolean = false): Shell {
- Shell.enableVerboseLogging = BuildConfig.DEBUG
- val builder = Shell.Builder.create()
- return try {
- if (globalMnt) {
- builder.build(getKsuDaemonPath(), "debug", "su", "-g")
- } else {
- builder.build(getKsuDaemonPath(), "debug", "su")
- }
- } catch (e: Throwable) {
- Log.w(TAG, "ksu failed: ", e)
- try {
- if (globalMnt) {
- builder.build("su", "-mm")
- } else {
- builder.build("su")
- }
- } catch (e: Throwable) {
- Log.e(TAG, "su failed: ", e)
- builder.build("sh")
- }
+ return runCatching {
+ createRootShellBuilder(globalMnt).build()
+ }.getOrElse { e ->
+ Log.w(TAG, "su failed: ", e)
+ Shell.Builder.create().apply {
+ if (globalMnt) setFlags(Shell.FLAG_MOUNT_MASTER)
+ }.build()
}
}
fun execKsud(args: String, newShell: Boolean = false): Boolean {
return if (newShell) {
withNewRootShell {
- ShellUtils.fastCmdResult(this, "${getKsuDaemonPath()} $args")
+ ShellUtils.fastCmdResult(this, "$ksuDaemonPath $args")
}
} else {
- ShellUtils.fastCmdResult(getRootShell(), "${getKsuDaemonPath()} $args")
+ ShellUtils.fastCmdResult("$ksuDaemonPath $args")
}
}
@@ -105,19 +96,15 @@ fun install() {
}
fun listModules(): String {
- val shell = getRootShell()
-
val out =
- shell.newJob().add("${getKsuDaemonPath()} module list").to(ArrayList(), null).exec().out
+ Shell.cmd("$ksuDaemonPath module list").to(ArrayList(), null).exec().out
return out.joinToString("\n").ifBlank { "[]" }
}
fun getModuleCount(): Int {
- val result = listModules()
- runCatching {
- val array = JSONArray(result)
- return array.length()
- }.getOrElse { return 0 }
+ return runCatching {
+ JSONArray(listModules()).length()
+ }.getOrDefault(0)
}
fun getSuperuserCount(): Int {
@@ -185,7 +172,7 @@ fun flashModule(
this?.copyTo(output)
}
val cmd = "module install ${file.absolutePath}"
- val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr)
+ val result = flashWithIO("$ksuDaemonPath $cmd", onStdout, onStderr)
Log.i("KernelSU", "install module $uri result: $result")
file.delete()
@@ -212,7 +199,7 @@ fun runModuleAction(
}
}
- val result = shell.newJob().add("${getKsuDaemonPath()} module action $moduleId")
+ val result = shell.newJob().add("$ksuDaemonPath module action $moduleId")
.to(stdoutCallback, stderrCallback).exec()
Log.i("KernelSU", "Module runAction result: $result")
@@ -224,7 +211,7 @@ fun restoreBoot(
): Boolean {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libzakoboot.so")
val result = flashWithIO(
- "${getKsuDaemonPath()} boot-restore -f --magiskboot $magiskboot",
+ "$ksuDaemonPath boot-restore -f --magiskboot $magiskboot",
onStdout,
onStderr
)
@@ -237,7 +224,7 @@ fun uninstallPermanently(
): Boolean {
val magiskboot = File(ksuApp.applicationInfo.nativeLibraryDir, "libzakoboot.so")
val result =
- flashWithIO("${getKsuDaemonPath()} uninstall --magiskboot $magiskboot", onStdout, onStderr)
+ flashWithIO("$ksuDaemonPath uninstall --magiskboot $magiskboot", onStdout, onStderr)
onFinish(result.isSuccess, result.code)
return result.isSuccess
}
@@ -312,7 +299,7 @@ fun installBoot(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
cmd += " -o $downloadsDir"
- val result = flashWithIO("${getKsuDaemonPath()} $cmd", onStdout, onStderr)
+ val result = flashWithIO("$ksuDaemonPath $cmd", onStdout, onStderr)
Log.i("KernelSU", "install boot result: ${result.isSuccess}")
bootFile?.delete()
@@ -324,22 +311,17 @@ fun installBoot(
}
fun reboot(reason: String = "") {
- val shell = getRootShell()
if (reason == "recovery") {
// KEYCODE_POWER = 26, hide incorrect "Factory data reset" message
- ShellUtils.fastCmd(shell, "/system/bin/input keyevent 26")
+ ShellUtils.fastCmdResult("/system/bin/input keyevent 26")
}
- ShellUtils.fastCmd(shell, "/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
+ ShellUtils.fastCmdResult("/system/bin/svc power reboot $reason || /system/bin/reboot $reason")
}
-fun rootAvailable(): Boolean {
- val shell = getRootShell()
- return shell.isRoot
-}
+fun rootAvailable() = Shell.isAppGrantedRoot() == true
fun isAbDevice(): Boolean {
- val shell = getRootShell()
- return ShellUtils.fastCmd(shell, "getprop ro.build.ab_update").trim().toBoolean()
+ return ShellUtils.fastCmd("getprop ro.build.ab_update").trim().toBoolean()
}
fun isInitBoot(): Boolean {
@@ -347,91 +329,77 @@ fun isInitBoot(): Boolean {
}
suspend fun getCurrentKmi(): String = withContext(Dispatchers.IO) {
- val shell = getRootShell()
val cmd = "boot-info current-kmi"
- ShellUtils.fastCmd(shell, "${getKsuDaemonPath()} $cmd")
+ ShellUtils.fastCmd("$ksuDaemonPath $cmd")
}
suspend fun getSupportedKmis(): List = withContext(Dispatchers.IO) {
- val shell = getRootShell()
val cmd = "boot-info supported-kmi"
- val out = shell.newJob().add("${getKsuDaemonPath()} $cmd").to(ArrayList(), null).exec().out
+ val out = Shell.cmd("$ksuDaemonPath $cmd").to(ArrayList(), null).exec().out
out.filter { it.isNotBlank() }.map { it.trim() }
}
fun hasMagisk(): Boolean {
- val shell = getRootShell(true)
- val result = shell.newJob().add("which magisk").exec()
- Log.i(TAG, "has magisk: ${result.isSuccess}")
- return result.isSuccess
+ val result = ShellUtils.fastCmdResult("which magisk")
+ Log.i(TAG, "has magisk: $result")
+ return result
}
fun isSepolicyValid(rules: String?): Boolean {
if (rules == null) {
return true
}
- val shell = getRootShell()
val result =
- shell.newJob().add("${getKsuDaemonPath()} sepolicy check '$rules'").to(ArrayList(), null)
+ Shell.cmd("$ksuDaemonPath sepolicy check '$rules'").to(ArrayList(), null)
.exec()
return result.isSuccess
}
fun getSepolicy(pkg: String): String {
- val shell = getRootShell()
val result =
- shell.newJob().add("${getKsuDaemonPath()} profile get-sepolicy $pkg").to(ArrayList(), null)
+ Shell.cmd("$ksuDaemonPath profile get-sepolicy $pkg").to(ArrayList(), null)
.exec()
Log.i(TAG, "code: ${result.code}, out: ${result.out}, err: ${result.err}")
return result.out.joinToString("\n")
}
fun setSepolicy(pkg: String, rules: String): Boolean {
- val shell = getRootShell()
- val result = shell.newJob().add("${getKsuDaemonPath()} profile set-sepolicy $pkg '$rules'")
+ val result = Shell.cmd("$ksuDaemonPath profile set-sepolicy $pkg '$rules'")
.to(ArrayList(), null).exec()
Log.i(TAG, "set sepolicy result: ${result.code}")
return result.isSuccess
}
fun listAppProfileTemplates(): List {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile list-templates").to(ArrayList(), null)
+ return Shell.cmd("$ksuDaemonPath profile list-templates").to(ArrayList(), null)
.exec().out
}
fun getAppProfileTemplate(id: String): String {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile get-template '${id}'")
+ return Shell.cmd("$ksuDaemonPath profile get-template '${id}'")
.to(ArrayList(), null).exec().out.joinToString("\n")
}
fun setAppProfileTemplate(id: String, template: String): Boolean {
- val shell = getRootShell()
val escapedTemplate = template.replace("\"", "\\\"")
- val cmd = """${getKsuDaemonPath()} profile set-template "$id" "$escapedTemplate'""""
- return shell.newJob().add(cmd)
+ val cmd = """$ksuDaemonPath profile set-template "$id" "$escapedTemplate'""""
+ return Shell.cmd(cmd)
.to(ArrayList(), null).exec().isSuccess
}
fun deleteAppProfileTemplate(id: String): Boolean {
- val shell = getRootShell()
- return shell.newJob().add("${getKsuDaemonPath()} profile delete-template '${id}'")
+ return Shell.cmd("$ksuDaemonPath profile delete-template '${id}'")
.to(ArrayList(), null).exec().isSuccess
}
fun forceStopApp(packageName: String) {
- val shell = getRootShell()
- val result = shell.newJob().add("am force-stop $packageName").exec()
+ val result = Shell.cmd("am force-stop $packageName").exec()
Log.i(TAG, "force stop $packageName result: $result")
}
fun launchApp(packageName: String) {
-
- val shell = getRootShell()
val result =
- shell.newJob()
- .add("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n")
+ Shell.cmd("cmd package resolve-activity --brief $packageName | tail -n 1 | xargs cmd activity start-activity -n")
.exec()
Log.i(TAG, "launch $packageName result: $result")
}
@@ -441,131 +409,90 @@ fun restartApp(packageName: String) {
launchApp(packageName)
}
-fun getSuSFSDaemonPath(): String {
- return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libzakozakozako.so"
+val suSFSDaemonPath by lazy {
+ "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libzakozakozako.so"
}
fun getSuSFS(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} support")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath support")
}
fun getSuSFSVersion(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} version")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath version")
}
fun getSuSFSVariant(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} variant")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath variant")
}
fun getSuSFSFeatures(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} features")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath features")
}
fun susfsSUS_SU_0(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 0")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath sus_su 0")
}
fun susfsSUS_SU_2(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su 2")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath sus_su 2")
}
fun susfsSUS_SU_Mode(): String {
- val shell = getRootShell()
- val result = ShellUtils.fastCmd(shell, "${getSuSFSDaemonPath()} sus_su mode")
- return result
+ return ShellUtils.fastCmd("$suSFSDaemonPath sus_su mode")
}
-fun getKpmmgrPath(): String {
- return ksuApp.applicationInfo.nativeLibraryDir + File.separator + "libkpmmgr.so"
+val kpmmgrPath by lazy {
+ "${ksuApp.applicationInfo.nativeLibraryDir}${File.separator}libkpmmgr.so"
}
fun loadKpmModule(path: String, args: String? = null): String {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} load $path ${args ?: ""}"
- return ShellUtils.fastCmd(shell, cmd)
+ return ShellUtils.fastCmd("$kpmmgrPath load $path ${args ?: ""}")
}
fun unloadKpmModule(name: String): String {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} unload $name"
- return ShellUtils.fastCmd(shell, cmd)
+ return ShellUtils.fastCmd("$kpmmgrPath unload $name")
}
fun getKpmModuleCount(): Int {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} num"
- val result = ShellUtils.fastCmd(shell, cmd)
+ val result = ShellUtils.fastCmd("$kpmmgrPath num")
return result.trim().toIntOrNull() ?: 0
}
-fun runCmd(shell: Shell, cmd: String): String {
- return shell.newJob()
- .add(cmd)
+fun runCmd(cmd: String): String {
+ return Shell.cmd(cmd)
.to(mutableListOf(), null)
.exec().out
.joinToString("\n")
}
fun listKpmModules(): String {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} list"
- return try {
- runCmd(shell, cmd).trim()
- } catch (e: Exception) {
- Log.e(TAG, "Failed to list KPM modules", e)
- ""
- }
+ return runCmd("$kpmmgrPath list").trim()
}
fun getKpmModuleInfo(name: String): String {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} info $name"
- return try {
- runCmd(shell, cmd).trim()
- } catch (e: Exception) {
- Log.e(TAG, "Failed to get KPM module info: $name", e)
- ""
- }
+ return runCmd("$kpmmgrPath info $name").trim()
}
fun controlKpmModule(name: String, args: String? = null): Int {
- val shell = getRootShell()
- val cmd = """${getKpmmgrPath()} control $name "${args ?: ""}""""
- val result = runCmd(shell, cmd)
+ val result = runCmd("""$kpmmgrPath control $name "${args ?: ""}"""")
return result.trim().toIntOrNull() ?: -1
}
fun getKpmVersion(): String {
- val shell = getRootShell()
- val cmd = "${getKpmmgrPath()} version"
- val result = ShellUtils.fastCmd(shell, cmd)
- return result.trim()
+ return ShellUtils.fastCmd("$kpmmgrPath version").trim()
}
fun getZygiskImplement(): String {
- val shell = getRootShell()
val zygiskPath = "/data/adb/modules/zygisksu"
val rezygiskPath = "/data/adb/modules/rezygisk"
- val result = if (ShellUtils.fastCmdResult(shell, "test -f $zygiskPath/module.prop && test ! -f $zygiskPath/disable")) {
- ShellUtils.fastCmd(shell, "grep '^name=' $zygiskPath/module.prop | cut -d'=' -f2")
- } else if (ShellUtils.fastCmdResult(shell, "test -f $rezygiskPath/module.prop && test ! -f $rezygiskPath/disable")) {
- ShellUtils.fastCmd(shell, "grep '^name=' $rezygiskPath/module.prop | cut -d'=' -f2")
- } else {
- "None"
- }
+ val result = when {
+ SuFile(zygiskPath, "module.prop").exists() && !SuFile(zygiskPath, "disable").exists() ->
+ ShellUtils.fastCmd("grep '^name=' $zygiskPath/module.prop | cut -d'=' -f2")
+ SuFile(rezygiskPath, "module.prop").exists() && !SuFile(rezygiskPath, "disable").exists() ->
+ ShellUtils.fastCmd("grep '^name=' $rezygiskPath/module.prop | cut -d'=' -f2")
+ else -> "None"
+ }.trim()
Log.i(TAG, "Zygisk implement: $result")
return result
}
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt
index 758cc2b8..fd1885e0 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/LogEvent.kt
@@ -3,9 +3,10 @@ package com.sukisu.ultra.ui.util
import android.content.Context
import android.os.Build
import android.system.Os
-import com.topjohnwu.superuser.ShellUtils
import com.sukisu.ultra.Natives
import com.sukisu.ultra.ui.screen.getManagerVersion
+import com.topjohnwu.superuser.Shell
+import com.topjohnwu.superuser.ShellUtils
import java.io.File
import java.io.FileWriter
import java.io.PrintWriter
@@ -38,30 +39,28 @@ fun getBugreportFile(context: Context): File {
val bootConfig = File(bugreportDir, "boot_config.txt")
val kernelConfig = File(bugreportDir, "defconfig.gz")
- val shell = getRootShell(true)
+ Shell.cmd("dmesg > ${dmesgFile.absolutePath}").exec()
+ Shell.cmd("logcat -d > ${logcatFile.absolutePath}").exec()
+ Shell.cmd("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec()
+ Shell.cmd("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec()
+ Shell.cmd("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec()
+ Shell.cmd("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec()
+ Shell.cmd("tar -czf ${oplusFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
+ Shell.cmd("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec()
- shell.newJob().add("dmesg > ${dmesgFile.absolutePath}").exec()
- shell.newJob().add("logcat -d > ${logcatFile.absolutePath}").exec()
- shell.newJob().add("tar -czf ${tombstonesFile.absolutePath} -C /data/tombstones .").exec()
- shell.newJob().add("tar -czf ${dropboxFile.absolutePath} -C /data/system/dropbox .").exec()
- shell.newJob().add("tar -czf ${pstoreFile.absolutePath} -C /sys/fs/pstore .").exec()
- shell.newJob().add("tar -czf ${diagFile.absolutePath} -C /data/vendor/diag . --exclude=./minidump.gz").exec()
- shell.newJob().add("tar -czf ${oplusFile.absolutePath} -C /mnt/oplus/op2/media/log/boot_log/ .").exec()
- shell.newJob().add("tar -czf ${bootlogFile.absolutePath} -C /data/adb/ksu/log .").exec()
+ Shell.cmd("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()
+ Shell.cmd("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec()
+ Shell.cmd("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec()
+ Shell.cmd("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec()
+ Shell.cmd("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec()
+ Shell.cmd("cp /data/system/packages.list ${appListFile.absolutePath}").exec()
+ Shell.cmd("getprop > ${propFile.absolutePath}").exec()
+ Shell.cmd("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec()
+ Shell.cmd("cp /proc/modules ${procModules.absolutePath}").exec()
+ Shell.cmd("cp /proc/bootconfig ${bootConfig.absolutePath}").exec()
+ Shell.cmd("cp /proc/config.gz ${kernelConfig.absolutePath}").exec()
- shell.newJob().add("cat /proc/1/mountinfo > ${mountsFile.absolutePath}").exec()
- shell.newJob().add("cat /proc/filesystems > ${fileSystemsFile.absolutePath}").exec()
- shell.newJob().add("busybox tree /data/adb > ${adbFileTree.absolutePath}").exec()
- shell.newJob().add("ls -alRZ /data/adb > ${adbFileDetails.absolutePath}").exec()
- shell.newJob().add("du -sh /data/adb/ksu/* > ${ksuFileSize.absolutePath}").exec()
- shell.newJob().add("cp /data/system/packages.list ${appListFile.absolutePath}").exec()
- shell.newJob().add("getprop > ${propFile.absolutePath}").exec()
- shell.newJob().add("cp /data/adb/ksu/.allowlist ${allowListFile.absolutePath}").exec()
- shell.newJob().add("cp /proc/modules ${procModules.absolutePath}").exec()
- shell.newJob().add("cp /proc/bootconfig ${bootConfig.absolutePath}").exec()
- shell.newJob().add("cp /proc/config.gz ${kernelConfig.absolutePath}").exec()
-
- val selinux = ShellUtils.fastCmd(shell, "getenforce")
+ val selinux = ShellUtils.fastCmd("getenforce")
// basic information
val buildInfo = File(bugreportDir, "basic.txt")
@@ -102,9 +101,9 @@ fun getBugreportFile(context: Context): File {
val targetFile = File(context.cacheDir, "KernelSU_bugreport_${current}.tar.gz")
- shell.newJob().add("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec()
- shell.newJob().add("rm -rf ${bugreportDir.absolutePath}").exec()
- shell.newJob().add("chmod 0644 ${targetFile.absolutePath}").exec()
+ Shell.cmd("tar czf ${targetFile.absolutePath} -C ${bugreportDir.absolutePath} .").exec()
+ Shell.cmd("rm -rf ${bugreportDir.absolutePath}").exec()
+ Shell.cmd("chmod 0644 ${targetFile.absolutePath}").exec()
return targetFile
}
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt
index 120939a3..190ce9c4 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleModify.kt
@@ -9,17 +9,16 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.platform.LocalContext
+import com.sukisu.ultra.R
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import com.sukisu.ultra.R
import java.io.BufferedReader
import java.io.IOException
import java.io.InputStreamReader
import java.text.SimpleDateFormat
-import java.util.Date
-import java.util.Locale
+import java.util.*
object ModuleModify {
@Composable
@@ -442,8 +441,4 @@ object ModuleModify {
type = "application/octet-stream"
}
}
-
- private fun reboot() {
- Runtime.getRuntime().exec(arrayOf("su", "-c", "reboot"))
- }
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt
index 49e86deb..230b99f5 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleUtils.kt
@@ -3,13 +3,13 @@ package com.sukisu.ultra.ui.util
import android.content.Context
import android.content.Intent
import android.net.Uri
+import android.util.Log
+import com.sukisu.ultra.R
import java.io.BufferedReader
+import java.io.IOException
import java.io.InputStreamReader
import java.nio.charset.StandardCharsets
import java.util.zip.ZipInputStream
-import com.sukisu.ultra.R
-import android.util.Log
-import java.io.IOException
object ModuleUtils {
private const val TAG = "ModuleUtils"
@@ -108,10 +108,7 @@ object ModuleUtils {
return try {
- val inputStream = context.contentResolver.openInputStream(uri)
- if (inputStream == null) {
- return null
- }
+ val inputStream = context.contentResolver.openInputStream(uri) ?: return null
val zipInputStream = ZipInputStream(inputStream)
var entry = zipInputStream.nextEntry
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt
index 9e70c40b..6f7ce6e6 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/ModuleVerificationManager.kt
@@ -4,6 +4,7 @@ import android.content.Context
import android.net.Uri
import android.util.Log
import com.sukisu.ultra.Natives
+import com.topjohnwu.superuser.Shell
import java.io.File
import java.io.FileOutputStream
@@ -124,18 +125,17 @@ object ModuleVerificationManager {
// 为指定模块创建验证标志文件
fun createVerificationFlag(moduleId: String): Boolean {
return try {
- val shell = getRootShell()
val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId"
// 确保目录存在
val createDirCommand = "mkdir -p '$VERIFICATION_FLAGS_DIR'"
- shell.newJob().add(createDirCommand).exec()
+ Shell.cmd(createDirCommand).exec()
// 创建验证标志文件,写入验证时间戳
val timestamp = System.currentTimeMillis()
val command = "echo '$timestamp' > '$flagFilePath'"
- val result = shell.newJob().add(command).exec()
+ val result = Shell.cmd(command).exec()
if (result.isSuccess) {
Log.d(TAG, "验证标志文件创建成功: $flagFilePath")
@@ -152,11 +152,10 @@ object ModuleVerificationManager {
fun removeVerificationFlag(moduleId: String): Boolean {
return try {
- val shell = getRootShell()
val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId"
val command = "rm -f '$flagFilePath'"
- val result = shell.newJob().add(command).exec()
+ val result = Shell.cmd(command).exec()
if (result.isSuccess) {
Log.d(TAG, "验证标志文件移除成功: $flagFilePath")
@@ -173,11 +172,10 @@ object ModuleVerificationManager {
fun getVerificationTimestamp(moduleId: String): Long {
return try {
- val shell = getRootShell()
val flagFilePath = "$VERIFICATION_FLAGS_DIR/$moduleId"
val command = "cat '$flagFilePath' 2>/dev/null || echo '0'"
- val result = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val result = Shell.cmd(command).to(ArrayList(), null).exec()
if (result.isSuccess && result.out.isNotEmpty()) {
val timestampStr = result.out.firstOrNull()?.trim() ?: "0"
@@ -195,12 +193,11 @@ object ModuleVerificationManager {
if (moduleIds.isEmpty()) return emptyMap()
return try {
- val shell = getRootShell()
val result = mutableMapOf()
// 确保目录存在
val createDirCommand = "mkdir -p '$VERIFICATION_FLAGS_DIR'"
- shell.newJob().add(createDirCommand).exec()
+ Shell.cmd(createDirCommand).exec()
// 批量检查所有模块的验证标志文件
val commands = moduleIds.map { moduleId ->
@@ -208,7 +205,7 @@ object ModuleVerificationManager {
}
val command = commands.joinToString(" && ")
- val shellResult = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val shellResult = Shell.cmd(command).to(ArrayList(), null).exec()
if (shellResult.isSuccess) {
shellResult.out.forEach { line ->
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt
index dff51722..b7e5216f 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SELinuxChecker.kt
@@ -1,31 +1,19 @@
package com.sukisu.ultra.ui.util
import android.content.Context
-import com.topjohnwu.superuser.Shell
import com.sukisu.ultra.R
+import com.topjohnwu.superuser.io.SuFile
-fun getSELinuxStatus(context: Context): String {
- val shell = Shell.Builder.create().build("sh")
- val list = ArrayList()
-
- val result = shell.use {
- it.newJob().add("getenforce").to(list, list).exec()
- }
-
- val output = list.joinToString("\n").trim()
-
- return if (result.isSuccess) {
- when (output) {
- "Enforcing" -> context.getString(R.string.selinux_status_enforcing)
- "Permissive" -> context.getString(R.string.selinux_status_permissive)
- "Disabled" -> context.getString(R.string.selinux_status_disabled)
+fun getSELinuxStatus(context: Context) = SuFile("/sys/fs/selinux/enforce").run {
+ when {
+ !exists() -> context.getString(R.string.selinux_status_disabled)
+ !isFile -> context.getString(R.string.selinux_status_unknown)
+ !canRead() -> context.getString(R.string.selinux_status_enforcing)
+ else -> when (runCatching { newInputStream() }.getOrNull()?.bufferedReader()
+ ?.use { it.runCatching { readLine() }.getOrNull()?.trim()?.toIntOrNull() }) {
+ 1 -> context.getString(R.string.selinux_status_enforcing)
+ 0 -> context.getString(R.string.selinux_status_permissive)
else -> context.getString(R.string.selinux_status_unknown)
}
- } else {
- if (output.contains("Permission denied")) {
- context.getString(R.string.selinux_status_enforcing)
- } else {
- context.getString(R.string.selinux_status_unknown)
- }
}
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt
index 0da7793e..40e6264e 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/util/SuSFSManager.kt
@@ -7,22 +7,17 @@ import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.util.Log
import android.widget.Toast
+import androidx.core.content.edit
import com.dergoogler.mmrl.platform.Platform.Companion.context
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.topjohnwu.superuser.Shell
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.withContext
+import kotlinx.coroutines.*
+import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
-import androidx.core.content.edit
-import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
@@ -430,12 +425,10 @@ object SuSFSManager {
async(Dispatchers.IO) {
val dataPath = "$MEDIA_DATA_PATH/${appInfo.packageName}"
val exists = try {
- val shell = getRootShell()
val outputList = mutableListOf()
val errorList = mutableListOf()
- val result = shell.newJob()
- .add("[ -d \"$dataPath\" ] && echo 'exists' || echo 'not_exists'")
+ val result = Shell.cmd("[ -d \"$dataPath\" ] && echo 'exists' || echo 'not_exists'")
.to(outputList, errorList)
.exec()
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt
index 8ccf7c82..838c2298 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/HomeViewModel.kt
@@ -8,6 +8,7 @@ import android.util.Log
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.core.content.edit
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dergoogler.mmrl.platform.Platform.Companion.context
@@ -22,7 +23,6 @@ import com.sukisu.ultra.ui.util.module.LatestVersionInfo
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import androidx.core.content.edit
class HomeViewModel : ViewModel() {
companion object {
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt
index 4d2948a1..36c5b437 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/KpmViewModel.kt
@@ -6,10 +6,10 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
+import com.sukisu.ultra.ui.util.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import com.sukisu.ultra.ui.util.*
/**
* @author ShirkNeko
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt
index f8dfe2e0..fef0f154 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/ModuleViewModel.kt
@@ -7,26 +7,26 @@ import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
+import androidx.core.content.edit
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dergoogler.mmrl.platform.model.ModuleConfig
import com.dergoogler.mmrl.platform.model.ModuleConfig.Companion.asModuleConfig
+import com.sukisu.ultra.ui.util.HanziToPinyin
+import com.sukisu.ultra.ui.util.ModuleVerificationManager
+import com.sukisu.ultra.ui.util.listModules
+import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import com.sukisu.ultra.ui.util.HanziToPinyin
-import com.sukisu.ultra.ui.util.listModules
-import com.sukisu.ultra.ui.util.getRootShell
-import com.sukisu.ultra.ui.util.ModuleVerificationManager
import kotlinx.coroutines.withContext
import org.json.JSONArray
import org.json.JSONObject
import java.text.Collator
import java.text.DecimalFormat
-import java.util.Locale
+import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.math.log10
import kotlin.math.pow
-import androidx.core.content.edit
/**
* @author ShirkNeko
@@ -452,9 +452,8 @@ class ModuleSizeCache(context: Context) {
*/
private fun calculateModuleFolderSize(dirId: String): Long {
return try {
- val shell = getRootShell()
val command = "du -sb /data/adb/modules/$dirId"
- val result = shell.newJob().add(command).to(ArrayList(), null).exec()
+ val result = Shell.cmd(command).to(ArrayList(), null).exec()
if (result.isSuccess && result.out.isNotEmpty()) {
val sizeStr = result.out.firstOrNull()?.split("\t")?.firstOrNull()
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt
index b3ac1eb8..0bd03203 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/SuperUserViewModel.kt
@@ -1,43 +1,29 @@
package com.sukisu.ultra.ui.viewmodel
-import android.content.ComponentName
-import android.content.Context
-import android.content.Intent
-import android.content.ServiceConnection
-import android.content.SharedPreferences
+import android.content.*
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.os.IBinder
import android.os.Parcelable
import android.os.SystemClock
import android.util.Log
-import androidx.compose.runtime.derivedStateOf
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.*
+import androidx.core.content.edit
import androidx.lifecycle.ViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import kotlinx.coroutines.async
-import kotlinx.coroutines.awaitAll
-import kotlinx.coroutines.supervisorScope
+import com.sukisu.ultra.Natives
+import com.sukisu.ultra.ksuApp
+import com.sukisu.ultra.ui.KsuService
+import com.sukisu.ultra.ui.util.HanziToPinyin
+import com.topjohnwu.superuser.Shell
+import kotlinx.coroutines.*
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.parcelize.Parcelize
-import com.sukisu.ultra.Natives
-import com.sukisu.ultra.ksuApp
-import com.sukisu.ultra.ui.util.HanziToPinyin
import java.text.Collator
import java.util.*
+import java.util.concurrent.LinkedBlockingQueue
import java.util.concurrent.ThreadPoolExecutor
import java.util.concurrent.TimeUnit
-import java.util.concurrent.LinkedBlockingQueue
-import androidx.core.content.edit
-import com.sukisu.ultra.ui.KsuService
-import com.sukisu.ultra.ui.util.KsuCli
-import com.topjohnwu.superuser.Shell
-import kotlinx.coroutines.asCoroutineDispatcher
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@@ -428,8 +414,7 @@ class SuperUserViewModel : ViewModel() {
Shell.EXECUTOR,
connection
)
- val shell = KsuCli.SHELL
- task?.let { shell.execTask(it) }
+ task?.let { Shell.getShell().execTask(it) }
} catch (e: Exception) {
Log.e(TAG, "Failed to bind KsuService", e)
continuation.resume(null)
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt
index 38f7577d..7aa5b945 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/viewmodel/TemplateViewModel.kt
@@ -7,21 +7,21 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.ViewModel
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import kotlinx.parcelize.Parcelize
import com.sukisu.ultra.Natives
import com.sukisu.ultra.profile.Capabilities
import com.sukisu.ultra.profile.Groups
import com.sukisu.ultra.ui.util.getAppProfileTemplate
import com.sukisu.ultra.ui.util.listAppProfileTemplates
import com.sukisu.ultra.ui.util.setAppProfileTemplate
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import kotlinx.parcelize.Parcelize
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONArray
import org.json.JSONObject
import java.text.Collator
-import java.util.Locale
+import java.util.*
import java.util.concurrent.TimeUnit
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt
index 0b4e76b2..7650defe 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/KsuLibSuProvider.kt
@@ -1,13 +1,13 @@
package com.sukisu.ultra.ui.webui
import android.content.ServiceConnection
-import android.util.Log
import android.content.pm.PackageInfo
+import android.util.Log
import com.dergoogler.mmrl.platform.Platform
import com.dergoogler.mmrl.platform.model.IProvider
import com.dergoogler.mmrl.platform.model.PlatformIntent
-import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.Natives
+import com.sukisu.ultra.ksuApp
import com.topjohnwu.superuser.ipc.RootService
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java
index 699c3706..263aa953 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/SuFilePathHandler.java
@@ -3,11 +3,9 @@ package com.sukisu.ultra.ui.webui;
import android.content.Context;
import android.util.Log;
import android.webkit.WebResourceResponse;
-
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import androidx.webkit.WebViewAssetLoader;
-
import com.topjohnwu.superuser.Shell;
import com.topjohnwu.superuser.io.SuFile;
import com.topjohnwu.superuser.io.SuFileInputStream;
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt
index 2aa03a0f..f1b77734 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIActivity.kt
@@ -16,16 +16,14 @@ import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.webkit.WebViewAssetLoader
import com.dergoogler.mmrl.platform.model.ModId
-import com.topjohnwu.superuser.Shell
+import com.dergoogler.mmrl.webui.interfaces.WXOptions
import com.sukisu.ultra.ui.util.createRootShell
import java.io.File
-import com.dergoogler.mmrl.webui.interfaces.WXOptions
@SuppressLint("SetJavaScriptEnabled")
class WebUIActivity : ComponentActivity() {
- private lateinit var webviewInterface: WebViewInterface
-
- private var rootShell: Shell? = null
+ private val rootShell by lazy { createRootShell(true) }
+ private var webView = null as WebView?
override fun onCreate(savedInstanceState: Bundle?) {
@@ -37,8 +35,8 @@ class WebUIActivity : ComponentActivity() {
super.onCreate(savedInstanceState)
- val moduleId = intent.getStringExtra("id")!!
- val name = intent.getStringExtra("name")!!
+ val moduleId = intent.getStringExtra("id") ?: finishAndRemoveTask().let { return }
+ val name = intent.getStringExtra("name") ?: finishAndRemoveTask().let { return }
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
@Suppress("DEPRECATION")
setTaskDescription(ActivityManager.TaskDescription("SukiSU-Ultra - $name"))
@@ -53,7 +51,6 @@ class WebUIActivity : ComponentActivity() {
val moduleDir = "/data/adb/modules/${moduleId}"
val webRoot = File("${moduleDir}/webroot")
- val rootShell = createRootShell(true).also { this.rootShell = it }
val webViewAssetLoader = WebViewAssetLoader.Builder()
.setDomain("mui.kernelsu.org")
.addPathHandler(
@@ -72,6 +69,8 @@ class WebUIActivity : ComponentActivity() {
}
val webView = WebView(this).apply {
+ webView = this
+
ViewCompat.setOnApplyWindowInsetsListener(this) { view, insets ->
val inset = insets.getInsets(WindowInsetsCompat.Type.systemBars())
view.updateLayoutParams {
@@ -85,8 +84,7 @@ class WebUIActivity : ComponentActivity() {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.allowFileAccess = false
- webviewInterface = WebViewInterface(WXOptions(this@WebUIActivity, this, ModId(moduleId)))
- addJavascriptInterface(webviewInterface, "ksu")
+ addJavascriptInterface(WebViewInterface(WXOptions(this@WebUIActivity, this, ModId(moduleId))), "ksu")
setWebViewClient(webViewClient)
loadUrl("https://mui.kernelsu.org/index.html")
}
@@ -95,7 +93,13 @@ class WebUIActivity : ComponentActivity() {
}
override fun onDestroy() {
+ rootShell.runCatching { close() }
+ webView?.apply {
+ stopLoading()
+ removeAllViews()
+ destroy()
+ webView = null
+ }
super.onDestroy()
- runCatching { rootShell?.close() }
}
}
\ No newline at end of file
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt
index bfe7ffed..85781a92 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebUIXActivity.kt
@@ -8,11 +8,7 @@ import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
+import androidx.compose.runtime.*
import androidx.lifecycle.lifecycleScope
import com.dergoogler.mmrl.platform.Platform
import com.dergoogler.mmrl.platform.model.ModId
diff --git a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt
index c4f9d4d7..23351042 100644
--- a/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt
+++ b/manager/app/src/main/java/com/sukisu/ultra/ui/webui/WebViewInterface.kt
@@ -12,18 +12,16 @@ import androidx.core.view.WindowInsetsControllerCompat
import com.dergoogler.mmrl.webui.interfaces.WXInterface
import com.dergoogler.mmrl.webui.interfaces.WXOptions
import com.dergoogler.mmrl.webui.model.JavaScriptInterface
+import com.sukisu.ultra.ui.util.*
import com.topjohnwu.superuser.CallbackList
import com.topjohnwu.superuser.ShellUtils
import com.topjohnwu.superuser.internal.UiThreadHandler
-import com.sukisu.ultra.ui.util.createRootShell
-import com.sukisu.ultra.ui.util.listModules
-import com.sukisu.ultra.ui.util.withNewRootShell
import org.json.JSONArray
import org.json.JSONObject
-import com.sukisu.ultra.ui.util.*
import java.io.File
import java.util.concurrent.CompletableFuture
+@Suppress("unused")
class WebViewInterface(
wxOptions: WXOptions,
) : WXInterface(wxOptions) {
@@ -68,56 +66,56 @@ class WebViewInterface(
options: String?,
callbackFunc: String
) {
- val finalCommand = StringBuilder()
- processOptions(finalCommand, options)
- finalCommand.append(cmd)
+ val finalCommand = buildString {
+ processOptions(this, options)
+ append(cmd)
+ }
val result = withNewRootShell(true) {
- newJob().add(finalCommand.toString()).to(ArrayList(), ArrayList()).exec()
+ newJob().add(finalCommand).to(ArrayList(), ArrayList()).exec()
}
val stdout = result.out.joinToString(separator = "\n")
val stderr = result.err.joinToString(separator = "\n")
val jsCode =
- "javascript: (function() { try { ${callbackFunc}(${result.code}, ${
+ "(function() { try { ${callbackFunc}(${result.code}, ${
JSONObject.quote(
stdout
)
}, ${JSONObject.quote(stderr)}); } catch(e) { console.error(e); } })();"
webView.post {
- webView.loadUrl(jsCode)
+ webView.evaluateJavascript(jsCode, null)
}
}
@JavascriptInterface
fun spawn(command: String, args: String, options: String?, callbackFunc: String) {
- val finalCommand = StringBuilder()
+ val finalCommand = buildString {
+ processOptions(this, options)
- processOptions(finalCommand, options)
-
- if (!TextUtils.isEmpty(args)) {
- finalCommand.append(command).append(" ")
- JSONArray(args).let { argsArray ->
- for (i in 0 until argsArray.length()) {
- finalCommand.append(argsArray.getString(i))
- finalCommand.append(" ")
+ if (!TextUtils.isEmpty(args)) {
+ append(command).append(" ")
+ JSONArray(args).let { argsArray ->
+ for (i in 0 until argsArray.length()) {
+ append("${argsArray.getString(i)} ")
+ }
}
+ } else {
+ append(command)
}
- } else {
- finalCommand.append(command)
}
val shell = createRootShell(true)
val emitData = fun(name: String, data: String) {
val jsCode =
- "javascript: (function() { try { ${callbackFunc}.${name}.emit('data', ${
+ "(function() { try { ${callbackFunc}.${name}.emit('data', ${
JSONObject.quote(
data
)
}); } catch(e) { console.error('emitData', e); } })();"
webView.post {
- webView.loadUrl(jsCode)
+ webView.evaluateJavascript(jsCode, null)
}
}
@@ -133,21 +131,21 @@ class WebViewInterface(
}
}
- val future = shell.newJob().add(finalCommand.toString()).to(stdout, stderr).enqueue()
+ val future = shell.newJob().add(finalCommand).to(stdout, stderr).enqueue()
val completableFuture = CompletableFuture.supplyAsync {
future.get()
}
completableFuture.thenAccept { result ->
val emitExitCode =
- "javascript: (function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();"
+ "(function() { try { ${callbackFunc}.emit('exit', ${result.code}); } catch(e) { console.error(`emitExit error: \${e}`); } })();"
webView.post {
- webView.loadUrl(emitExitCode)
+ webView.evaluateJavascript(emitExitCode, null)
}
if (result.code != 0) {
val emitErrCode =
- "javascript: (function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${
+ "(function() { try { var err = new Error(); err.exitCode = ${result.code}; err.message = ${
JSONObject.quote(
result.err.joinToString(
"\n"
@@ -155,7 +153,7 @@ class WebViewInterface(
)
};${callbackFunc}.emit('error', err); } catch(e) { console.error('emitErr', e); } })();"
webView.post {
- webView.loadUrl(emitErrCode)
+ webView.evaluateJavascript(emitErrCode, null)
}
}
}.whenComplete { _, _ ->
@@ -208,12 +206,12 @@ class WebViewInterface(
// =================== KPM支持 =============================
@JavascriptInterface
- fun listAllKpm() : String {
+ fun listAllKpm(): String {
return listKpmModules()
}
@JavascriptInterface
- fun controlKpm(name: String, args: String) : Int {
+ fun controlKpm(name: String, args: String): Int {
return controlKpmModule(name, args)
}
}
diff --git a/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java b/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java
index f829f614..68b85228 100644
--- a/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java
+++ b/manager/app/src/main/java/io/sukisu/ultra/UltraShellHelper.java
@@ -1,15 +1,13 @@
package io.sukisu.ultra;
-import java.util.ArrayList;
+import com.topjohnwu.superuser.Shell;
-import com.sukisu.ultra.ui.util.KsuCli;
+import java.util.ArrayList;
public class UltraShellHelper {
public static String runCmd(String cmds) {
StringBuilder sb = new StringBuilder();
- for(String str : KsuCli.INSTANCE.getGLOBAL_MNT_SHELL()
- .newJob()
- .add(cmds)
+ for(String str : Shell.cmd(cmds)
.to(new ArrayList<>(), null)
.exec()
.getOut()) {
@@ -18,11 +16,6 @@ public class UltraShellHelper {
return sb.toString();
}
- public static boolean isPathExists(String path) {
- String result = runCmd("test -f '" + path + "' && echo 'exists'");
- return result.contains("exists");
- }
-
public static void CopyFileTo(String path, String target) {
runCmd("cp -f '" + path + "' '" + target + "' 2>&1");
}
diff --git a/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java b/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java
index 3532915e..d6501b9e 100644
--- a/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java
+++ b/manager/app/src/main/java/io/sukisu/ultra/UltraToolInstall.java
@@ -1,5 +1,7 @@
package io.sukisu.ultra;
+import com.topjohnwu.superuser.io.SuFile;
+
import static com.sukisu.ultra.ui.util.KsuCliKt.getKpmmgrPath;
import static com.sukisu.ultra.ui.util.KsuCliKt.getSuSFSDaemonPath;
@@ -7,15 +9,17 @@ public class UltraToolInstall {
private static final String OUTSIDE_KPMMGR_PATH = "/data/adb/ksu/bin/kpmmgr";
private static final String OUTSIDE_SUSFSD_PATH = "/data/adb/ksu/bin/susfsd";
public static void tryToInstall() {
- String kpmmgrPath = getKpmmgrPath();
- if (UltraShellHelper.isPathExists(OUTSIDE_KPMMGR_PATH)) {
- UltraShellHelper.CopyFileTo(kpmmgrPath, OUTSIDE_KPMMGR_PATH);
- UltraShellHelper.runCmd("chmod a+rx " + OUTSIDE_KPMMGR_PATH);
+ SuFile KpmmgrFile = new SuFile(OUTSIDE_KPMMGR_PATH);
+ if (KpmmgrFile.exists()) {
+ UltraShellHelper.CopyFileTo(getKpmmgrPath(), OUTSIDE_KPMMGR_PATH);
+ boolean _ = KpmmgrFile.setReadable(true, false);
+ boolean _ = KpmmgrFile.setExecutable(true, false);
}
- String SuSFSDaemonPath = getSuSFSDaemonPath();
- if (UltraShellHelper.isPathExists(OUTSIDE_SUSFSD_PATH)) {
- UltraShellHelper.CopyFileTo(SuSFSDaemonPath, OUTSIDE_SUSFSD_PATH);
- UltraShellHelper.runCmd("chmod a+rx " + OUTSIDE_SUSFSD_PATH);
+ SuFile SuSFSDaemonFile = new SuFile(OUTSIDE_SUSFSD_PATH);
+ if (SuSFSDaemonFile.exists()) {
+ UltraShellHelper.CopyFileTo(getSuSFSDaemonPath(), OUTSIDE_SUSFSD_PATH);
+ boolean _ = SuSFSDaemonFile.setReadable(true, false);
+ boolean _ = SuSFSDaemonFile.setExecutable(true, false);
}
}
}
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt
index c0217eed..14e0c11c 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/component/BottomBar.kt
@@ -1,30 +1,28 @@
package zako.zako.zako.zakoui.activity.component
import android.annotation.SuppressLint
+import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
-import androidx.compose.runtime.*
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.collectAsState
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavHostController
+import com.ramcosta.composedestinations.generated.NavGraphs
+import com.ramcosta.composedestinations.spec.RouteOrDirection
import com.ramcosta.composedestinations.utils.isRouteOnBackStackAsState
import com.ramcosta.composedestinations.utils.rememberDestinationsNavigator
-import com.ramcosta.composedestinations.spec.RouteOrDirection
-import com.ramcosta.composedestinations.generated.NavGraphs
import com.sukisu.ultra.Natives
import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.MainActivity
-import zako.zako.zako.zakoui.activity.util.AppData
-import zako.zako.zako.zakoui.activity.util.AppData.getKpmVersionUse
import com.sukisu.ultra.ui.screen.BottomBarDestination
import com.sukisu.ultra.ui.theme.CardConfig.cardAlpha
import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
-import androidx.compose.foundation.layout.windowInsetsPadding
-import androidx.compose.foundation.layout.WindowInsets
-import androidx.compose.foundation.layout.WindowInsetsSides
-import androidx.compose.foundation.layout.only
-import androidx.compose.foundation.layout.navigationBars
+import zako.zako.zako.zakoui.activity.util.AppData
import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager
+import zako.zako.zako.zakoui.activity.util.AppData.getKpmVersionUse
@SuppressLint("ContextCastToActivity")
@OptIn(ExperimentalMaterial3Api::class)
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt
index 51e7f64d..3d364e48 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AnimatedBottomBar.kt
@@ -1,10 +1,6 @@
package zako.zako.zako.zakoui.activity.util
-import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.slideInVertically
-import androidx.compose.animation.slideOutVertically
+import androidx.compose.animation.*
import androidx.compose.runtime.Composable
object AnimatedBottomBar {
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt
index 54fea9d1..50f51368 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/AppData.kt
@@ -1,11 +1,7 @@
package zako.zako.zako.zakoui.activity.util
import com.sukisu.ultra.Natives
-import com.sukisu.ultra.ui.util.getKpmModuleCount
-import com.sukisu.ultra.ui.util.getKpmVersion
-import com.sukisu.ultra.ui.util.getModuleCount
-import com.sukisu.ultra.ui.util.getSuperuserCount
-import com.sukisu.ultra.ui.util.rootAvailable
+import com.sukisu.ultra.ui.util.*
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -84,13 +80,6 @@ object AppData {
}
}
- /**
- * 检查是否具有管理员权限
- */
- fun isManager(packageName: String): Boolean {
- return Natives.becomeManager(packageName)
- }
-
/**
* 检查是否是完整功能模式
*/
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt
index 0e9bd72f..e09b1949 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/DataRefreshUtils.kt
@@ -3,12 +3,12 @@ package zako.zako.zako.zakoui.activity.util
import android.content.Context
import androidx.lifecycle.LifecycleCoroutineScope
import com.sukisu.ultra.ui.MainActivity
-import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
+import zako.zako.zako.zakoui.activity.util.AppData.DataRefreshManager
object DataRefreshUtils {
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt
index 9ccd08b4..50debbc8 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/activity/util/LocaleUtils.kt
@@ -4,7 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.res.Configuration
import android.os.Build
-import java.util.Locale
+import java.util.*
object LocaleUtils {
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt
index 4faff202..1fb67a71 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/flash/KernelFlash.kt
@@ -6,7 +6,9 @@ import android.content.Context
import android.net.Uri
import androidx.documentfile.provider.DocumentFile
import com.sukisu.ultra.R
+import com.sukisu.ultra.ui.util.rootAvailable
import com.sukisu.ultra.utils.AssetsUtil
+import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
@@ -131,7 +133,7 @@ class HorizonKernelWorker(
if (isAbDevice && slot != null) {
state.updateStep(context.getString(R.string.horizon_getting_original_slot))
state.updateProgress(0.72f)
- originalSlot = runCommandGetOutput(true, "getprop ro.boot.slot_suffix")
+ originalSlot = runCommandGetOutput("getprop ro.boot.slot_suffix")
state.updateStep(context.getString(R.string.horizon_setting_target_slot))
state.updateProgress(0.74f)
@@ -165,13 +167,11 @@ class HorizonKernelWorker(
// 检查设备是否为AB分区设备
private fun isAbDevice(): Boolean {
- val abUpdate = runCommandGetOutput(true, "getprop ro.build.ab_update")?.trim() ?: ""
- if (abUpdate.equals("false", ignoreCase = true) || abUpdate.isEmpty()) {
- return false
- }
+ val abUpdate = runCommandGetOutput("getprop ro.build.ab_update")
+ if (!abUpdate.toBoolean()) return false
- val slotSuffix = runCommandGetOutput(true, "getprop ro.boot.slot_suffix")
- return !slotSuffix.isNullOrEmpty()
+ val slotSuffix = runCommandGetOutput("getprop ro.boot.slot_suffix")
+ return slotSuffix.isNotEmpty()
}
private fun cleanup() {
@@ -195,11 +195,10 @@ class HorizonKernelWorker(
}
}
- @SuppressLint("StringFormatInvalid")
private fun patch() {
- val kernelVersion = runCommandGetOutput(true, "cat /proc/version")
+ val kernelVersion = runCommandGetOutput("cat /proc/version")
val versionRegex = """\d+\.\d+\.\d+""".toRegex()
- val version = kernelVersion?.let { versionRegex.find(it) }?.value ?: ""
+ val version = kernelVersion.let { versionRegex.find(it) }?.value ?: ""
val toolName = if (version.isNotEmpty()) {
val parts = version.split('.')
if (parts.size >= 2) {
@@ -286,28 +285,7 @@ class HorizonKernelWorker(
}
}
- private fun runCommandGetOutput(su: Boolean, cmd: String): String? {
- val shell = if (su) "su" else "sh"
- val process = Runtime.getRuntime().exec(arrayOf(shell, "-c", cmd))
-
- return try {
- process.inputStream.bufferedReader().use { reader ->
- reader.readText().trim()
- }
- } catch (_: Exception) {
- ""
- } finally {
- process.destroy()
- }
- }
-
- private fun rootAvailable(): Boolean {
- return try {
- val process = Runtime.getRuntime().exec("su -c true")
- val exitValue = process.waitFor()
- exitValue == 0
- } catch (_: Exception) {
- false
- }
+ private fun runCommandGetOutput(cmd: String): String {
+ return Shell.cmd(cmd).exec().out.joinToString("\n").trim()
}
}
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt
index 0c125c1d..50a94e24 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/KernelFlash.kt
@@ -19,6 +19,8 @@ import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.input.key.Key
+import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@@ -29,21 +31,20 @@ import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.sukisu.ultra.R
-import zako.zako.zako.zakoui.flash.HorizonKernelState
-import zako.zako.zako.zakoui.flash.HorizonKernelWorker
import com.sukisu.ultra.ui.component.KeyEventBlocker
-import com.sukisu.ultra.ui.util.*
+import com.sukisu.ultra.ui.theme.CardConfig
+import com.sukisu.ultra.ui.util.LocalSnackbarHost
+import com.sukisu.ultra.ui.util.reboot
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
+import zako.zako.zako.zakoui.flash.FlashState
+import zako.zako.zako.zakoui.flash.HorizonKernelState
+import zako.zako.zako.zakoui.flash.HorizonKernelWorker
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.key
-import com.sukisu.ultra.ui.theme.CardConfig
-import zako.zako.zako.zakoui.flash.FlashState
-import kotlinx.coroutines.delay
/**
* @author ShirkNeko
diff --git a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt
index 25565cf7..3dbd4f23 100644
--- a/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt
+++ b/manager/app/src/main/java/zako/zako/zako/zakoui/screen/MoreSettings.kt
@@ -9,89 +9,49 @@ import android.os.Build
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
-import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.*
import androidx.compose.animation.core.animateFloatAsState
-import androidx.compose.animation.expandVertically
-import androidx.compose.animation.fadeIn
-import androidx.compose.animation.fadeOut
-import androidx.compose.animation.shrinkVertically
-import androidx.compose.animation.slideInVertically
-import androidx.compose.animation.slideOutVertically
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.*
import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.verticalScroll
+import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.automirrored.filled.NavigateNext
import androidx.compose.material.icons.filled.*
-import androidx.compose.material3.AlertDialog
-import androidx.compose.material3.Button
-import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Scaffold
-import androidx.compose.material3.Slider
-import androidx.compose.material3.SliderDefaults
-import androidx.compose.material3.Text
-import androidx.compose.material3.TopAppBar
-import androidx.compose.material3.TopAppBarDefaults
-import androidx.compose.material3.rememberTopAppBarState
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableFloatStateOf
-import androidx.compose.runtime.mutableIntStateOf
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.material3.*
import androidx.compose.runtime.*
+import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import com.ramcosta.composedestinations.annotation.Destination
import com.ramcosta.composedestinations.annotation.RootGraph
+import com.ramcosta.composedestinations.navigation.DestinationsNavigator
import com.sukisu.ultra.Natives
import com.sukisu.ultra.R
+import com.sukisu.ultra.ksuApp
import com.sukisu.ultra.ui.component.ImageEditorDialog
import com.sukisu.ultra.ui.component.KsuIsValid
-import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.theme.*
+import com.sukisu.ultra.ui.theme.CardConfig.cardElevation
import com.sukisu.ultra.ui.util.*
import com.topjohnwu.superuser.Shell
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
-import java.util.Locale
+import java.util.*
import kotlin.math.roundToInt
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.icons.automirrored.filled.ArrowBack
-import androidx.compose.material.icons.automirrored.filled.NavigateNext
-import androidx.compose.material3.Card
-import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.OutlinedTextField
-import androidx.compose.material3.Switch
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.vector.ImageVector
-import com.sukisu.ultra.ui.theme.getCardColors
-import com.sukisu.ultra.ui.theme.getCardElevation
-import androidx.compose.material3.RadioButton
-import androidx.compose.material3.TextButton
-import androidx.compose.runtime.saveable.rememberSaveable
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.unit.sp
-import com.ramcosta.composedestinations.navigation.DestinationsNavigator
-import com.sukisu.ultra.ksuApp
/**
* @author ShirkNeko
@@ -110,7 +70,7 @@ fun saveCardConfig(context: Context) {
/**
* 更多设置屏幕
*/
-@SuppressLint("LocalContextConfigurationRead", "ObsoleteSdkInt")
+@SuppressLint("LocalContextConfigurationRead", "LocalContextResourcesRead", "ObsoleteSdkInt")
@OptIn(ExperimentalMaterial3Api::class)
@Destination
@Composable