manager: Optimized import, optimized all libsu shell calls, and fixed WebUI memory leaks (#369)
* manager: simply optimize * manager: optimize webui functions * manager: detect selinux using libsu:io * manager: optimize webui functions * manager: use the default shell * manager: optimize import * manager: optimize shell builder * manager: fix memory leaks * manager: optimize magisk detection * manager: use libsu * manager: optimize webui --------- Co-authored-by: 白彩恋 <shiro@oom-wg.dev>
This commit is contained in:
@@ -12,10 +12,12 @@ import android.os.Bundle
|
||||
import coil.Coil
|
||||
import coil.ImageLoader
|
||||
import com.dergoogler.mmrl.platform.Platform
|
||||
import com.sukisu.ultra.ui.util.createRootShellBuilder
|
||||
import com.topjohnwu.superuser.Shell
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconFetcher
|
||||
import me.zhanghai.android.appiconloader.coil.AppIconKeyer
|
||||
import java.io.File
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
lateinit var ksuApp: KernelSUApplication
|
||||
@@ -86,6 +88,8 @@ class KernelSUApplication : Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
ksuApp = this
|
||||
Shell.setDefaultBuilder(createRootShellBuilder(true))
|
||||
Shell.enableVerboseLogging = BuildConfig.DEBUG
|
||||
|
||||
// 注册Activity生命周期回调
|
||||
registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
|
||||
|
||||
@@ -2,11 +2,7 @@ package com.sukisu.ultra.ui
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageInfo
|
||||
import android.os.Binder
|
||||
import android.os.IBinder
|
||||
import android.os.IInterface
|
||||
import android.os.Parcel
|
||||
import android.os.UserManager
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import com.topjohnwu.superuser.ipc.RootService
|
||||
import rikka.parcelablelist.ParcelableListSlice
|
||||
@@ -60,7 +56,7 @@ class KsuService : RootService() {
|
||||
val result = getPackages(flagsArg)
|
||||
reply?.writeNoException()
|
||||
reply?.writeInt(1)
|
||||
result.writeToParcel(reply!!, android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE)
|
||||
result.writeToParcel(reply!!, Parcelable.PARCELABLE_WRITE_RETURN_VALUE)
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,18 +7,15 @@ import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.animation.AnimatedContentTransitionScope
|
||||
import androidx.compose.animation.EnterTransition
|
||||
import androidx.compose.animation.ExitTransition
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.scaleOut
|
||||
import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHostState
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.NavBackStackEntry
|
||||
@@ -29,20 +26,19 @@ import com.ramcosta.composedestinations.animations.NavHostAnimatedDestinationSty
|
||||
import com.ramcosta.composedestinations.generated.NavGraphs
|
||||
import com.ramcosta.composedestinations.generated.destinations.ExecuteModuleActionScreenDestination
|
||||
import com.ramcosta.composedestinations.spec.NavHostGraphSpec
|
||||
import io.sukisu.ultra.UltraToolInstall
|
||||
import com.sukisu.ultra.ksuApp
|
||||
import zako.zako.zako.zakoui.activity.util.AppData
|
||||
import com.sukisu.ultra.Natives
|
||||
import com.sukisu.ultra.ui.screen.BottomBarDestination
|
||||
import com.sukisu.ultra.ui.theme.*
|
||||
import zako.zako.zako.zakoui.activity.util.*
|
||||
import zako.zako.zako.zakoui.activity.component.BottomBar
|
||||
import com.sukisu.ultra.ui.theme.KernelSUTheme
|
||||
import com.sukisu.ultra.ui.util.LocalSnackbarHost
|
||||
import com.sukisu.ultra.ui.util.install
|
||||
import com.sukisu.ultra.ui.viewmodel.HomeViewModel
|
||||
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
|
||||
import com.sukisu.ultra.ui.webui.initPlatform
|
||||
import io.sukisu.ultra.UltraToolInstall
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.launch
|
||||
import zako.zako.zako.zakoui.activity.component.BottomBar
|
||||
import zako.zako.zako.zakoui.activity.util.*
|
||||
|
||||
class MainActivity : ComponentActivity() {
|
||||
private lateinit var superUserViewModel: SuperUserViewModel
|
||||
@@ -206,7 +202,7 @@ class MainActivity : ComponentActivity() {
|
||||
// 初始化主题相关设置
|
||||
ThemeUtils.initializeThemeSettings(this, settingsStateFlow)
|
||||
|
||||
val isManager = AppData.isManager(ksuApp.packageName)
|
||||
val isManager = Natives.becomeManager(packageName)
|
||||
if (isManager) {
|
||||
install()
|
||||
UltraToolInstall.tryToInstall()
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
package com.sukisu.ultra.ui.component
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
@@ -21,11 +14,7 @@ import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.res.colorResource
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.SpanStyle
|
||||
import androidx.compose.ui.text.TextLinkStyles
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.fromHtml
|
||||
import androidx.compose.ui.text.*
|
||||
import androidx.compose.ui.text.style.TextDecoration
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -95,7 +84,7 @@ private fun AboutCardContent() {
|
||||
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
|
||||
val annotatedString = AnnotatedString.Companion.fromHtml(
|
||||
val annotatedString = AnnotatedString.fromHtml(
|
||||
htmlString = stringResource(
|
||||
id = R.string.about_source_code,
|
||||
"<b><a href=\"https://github.com/ShirkNeko/SukiSU-Ultra\">GitHub</a></b>",
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package com.sukisu.ultra.ui.component
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
||||
@@ -10,15 +10,20 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Fullscreen
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -30,10 +35,6 @@ import com.sukisu.ultra.R
|
||||
import com.sukisu.ultra.ui.util.BackgroundTransformation
|
||||
import com.sukisu.ultra.ui.util.saveTransformedBackground
|
||||
import kotlinx.coroutines.launch
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.layout.onSizeChanged
|
||||
import kotlin.math.max
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -4,35 +4,15 @@ import android.util.Log
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.layout.Box
|
||||
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.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.outlined.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
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.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.focus.FocusRequester
|
||||
|
||||
@@ -3,12 +3,7 @@ package com.sukisu.ultra.ui.component
|
||||
import androidx.compose.foundation.LocalIndication
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.selection.toggleable
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.RadioButton
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
|
||||
@@ -5,18 +5,18 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.horizontalScroll
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.SdStorage
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sukisu.ultra.R
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.SdStorage
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
|
||||
/**
|
||||
* 槽位选择对话框组件
|
||||
|
||||
@@ -5,62 +5,15 @@ import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
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.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
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.filled.CheckCircle
|
||||
import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material.icons.filled.Edit
|
||||
import androidx.compose.material.icons.filled.Folder
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.RadioButtonUnchecked
|
||||
import androidx.compose.material.icons.filled.Search
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Update
|
||||
import androidx.compose.material.icons.filled.Visibility
|
||||
import androidx.compose.material.icons.filled.VisibilityOff
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
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.OutlinedTextField
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
|
||||
@@ -1,37 +1,13 @@
|
||||
package com.sukisu.ultra.ui.component
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Apps
|
||||
import androidx.compose.material.icons.filled.Folder
|
||||
import androidx.compose.material.icons.filled.Loop
|
||||
import androidx.compose.material.icons.filled.PlayArrow
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.material.icons.filled.Storage
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.remember
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.sukisu.ultra.ui.component
|
||||
|
||||
import androidx.compose.animation.*
|
||||
import androidx.compose.animation.core.*
|
||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||
import androidx.compose.animation.core.animateFloatAsState
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
@@ -15,8 +17,8 @@ import androidx.compose.ui.draw.scale
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.sukisu.ultra.R
|
||||
|
||||
// 菜单项数据类
|
||||
|
||||
@@ -3,11 +3,7 @@ package com.sukisu.ultra.ui.component.profile
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
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.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
||||
@@ -1,28 +1,11 @@
|
||||
package com.sukisu.ultra.ui.component.profile
|
||||
|
||||
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.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.AssistChip
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedCard
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -34,11 +17,7 @@ import androidx.core.text.isDigitsOnly
|
||||
import com.maxkeppeker.sheets.core.models.base.Header
|
||||
import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState
|
||||
import com.maxkeppeler.sheets.input.InputDialog
|
||||
import com.maxkeppeler.sheets.input.models.InputHeader
|
||||
import com.maxkeppeler.sheets.input.models.InputSelection
|
||||
import com.maxkeppeler.sheets.input.models.InputTextField
|
||||
import com.maxkeppeler.sheets.input.models.InputTextFieldType
|
||||
import com.maxkeppeler.sheets.input.models.ValidationResult
|
||||
import com.maxkeppeler.sheets.input.models.*
|
||||
import com.maxkeppeler.sheets.list.ListDialog
|
||||
import com.maxkeppeler.sheets.list.models.ListOption
|
||||
import com.maxkeppeler.sheets.list.models.ListSelection
|
||||
|
||||
@@ -6,21 +6,9 @@ import androidx.compose.material.icons.automirrored.filled.ReadMore
|
||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||
import androidx.compose.material.icons.filled.ArrowDropUp
|
||||
import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExposedDropdownMenuBox
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MenuAnchorType
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Text
|
||||
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.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import com.sukisu.ultra.Natives
|
||||
|
||||
@@ -2,26 +2,9 @@ package com.sukisu.ultra.ui.screen
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.Crossfade
|
||||
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.gestures.detectTapGestures
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
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.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.width
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
@@ -29,31 +12,9 @@ import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.AccountCircle
|
||||
import androidx.compose.material.icons.filled.Android
|
||||
import androidx.compose.material.icons.filled.Security
|
||||
import androidx.compose.material3.DropdownMenu
|
||||
import androidx.compose.material3.DropdownMenuItem
|
||||
import androidx.compose.material3.ElevatedCard
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.FilterChip
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
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.SnackbarHost
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarColors
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
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.material3.*
|
||||
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.alpha
|
||||
@@ -86,12 +47,7 @@ import com.sukisu.ultra.ui.component.profile.TemplateConfig
|
||||
import com.sukisu.ultra.ui.theme.CardConfig
|
||||
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.forceStopApp
|
||||
import com.sukisu.ultra.ui.util.getSepolicy
|
||||
import com.sukisu.ultra.ui.util.launchApp
|
||||
import com.sukisu.ultra.ui.util.restartApp
|
||||
import com.sukisu.ultra.ui.util.setSepolicy
|
||||
import com.sukisu.ultra.ui.util.*
|
||||
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
|
||||
import com.sukisu.ultra.ui.viewmodel.getTemplateInfoById
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -386,7 +342,7 @@ private fun AppProfileInner(
|
||||
}
|
||||
}
|
||||
|
||||
private enum class Mode(@StringRes private val res: Int) {
|
||||
private enum class Mode(@param:StringRes private val res: Int) {
|
||||
Default(R.string.profile_default), Template(R.string.profile_template), Custom(R.string.profile_custom);
|
||||
|
||||
val text: String
|
||||
|
||||
@@ -3,20 +3,15 @@ package com.sukisu.ultra.ui.screen
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.*
|
||||
import androidx.compose.material.icons.filled.Archive
|
||||
import androidx.compose.material.icons.outlined.*
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import com.ramcosta.composedestinations.generated.destinations.HomeScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.ModuleScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.SuperUserScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.SettingScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.KpmScreenDestination
|
||||
import com.ramcosta.composedestinations.generated.destinations.*
|
||||
import com.ramcosta.composedestinations.spec.DirectionDestinationSpec
|
||||
import com.sukisu.ultra.R
|
||||
|
||||
enum class BottomBarDestination(
|
||||
val direction: DirectionDestinationSpec,
|
||||
@StringRes val label: Int,
|
||||
@param:StringRes val label: Int,
|
||||
val iconSelected: ImageVector,
|
||||
val iconNotSelected: ImageVector,
|
||||
val rootRequired: Boolean,
|
||||
|
||||
@@ -2,32 +2,15 @@ package com.sukisu.ultra.ui.screen
|
||||
|
||||
import android.os.Environment
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.safeDrawing
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.Save
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExtendedFloatingActionButton
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.SnackbarHost
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.key.Key
|
||||
import androidx.compose.ui.input.key.key
|
||||
@@ -37,17 +20,16 @@ import androidx.compose.ui.unit.dp
|
||||
import com.ramcosta.composedestinations.annotation.Destination
|
||||
import com.ramcosta.composedestinations.annotation.RootGraph
|
||||
import com.ramcosta.composedestinations.navigation.DestinationsNavigator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import com.sukisu.ultra.R
|
||||
import com.sukisu.ultra.ui.component.KeyEventBlocker
|
||||
import com.sukisu.ultra.ui.util.LocalSnackbarHost
|
||||
import com.sukisu.ultra.ui.util.runModuleAction
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.File
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
@Destination<RootGraph>
|
||||
|
||||
@@ -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.*
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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
|
||||
|
||||
// 应用优先级枚举
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -32,7 +32,8 @@ import java.util.Locale;
|
||||
* <p>
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ private data class LinkInfo(
|
||||
val end: Int
|
||||
)
|
||||
|
||||
@Suppress("HttpUrlsUsage")
|
||||
private fun extractUrls(text: String): List<LinkInfo> = buildList {
|
||||
val matcher = urlPattern.matcher(text)
|
||||
while (matcher.find()) {
|
||||
|
||||
@@ -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 <T> 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<String> = 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<String> {
|
||||
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<String>(), 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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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"))
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<String, Boolean>()
|
||||
|
||||
// 确保目录存在
|
||||
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 ->
|
||||
|
||||
@@ -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<String>()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<String>()
|
||||
val errorList = mutableListOf<String>()
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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<MarginLayoutParams> {
|
||||
@@ -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() }
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
processOptions(finalCommand, options)
|
||||
val finalCommand = buildString {
|
||||
processOptions(this, options)
|
||||
|
||||
if (!TextUtils.isEmpty(args)) {
|
||||
finalCommand.append(command).append(" ")
|
||||
append(command).append(" ")
|
||||
JSONArray(args).let { argsArray ->
|
||||
for (i in 0 until argsArray.length()) {
|
||||
finalCommand.append(argsArray.getString(i))
|
||||
finalCommand.append(" ")
|
||||
append("${argsArray.getString(i)} ")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
finalCommand.append(command)
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否是完整功能模式
|
||||
*/
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<RootGraph>
|
||||
@Composable
|
||||
|
||||
Reference in New Issue
Block a user