Add the function of obtaining and restoring the original slot, and display the current slot information in the slot selection dialog box

-It should be possible to fix the issue of selecting slot positions

Signed-off-by: ShirkNeko 109797057+ShirkNeko@users.noreply.github.com
This commit is contained in:
ShirkNeko
2025-04-27 19:35:55 +08:00
parent 85b4d11912
commit 6656604809
4 changed files with 118 additions and 1 deletions

View File

@@ -90,6 +90,7 @@ class HorizonKernelWorker(
private lateinit var binaryPath: String private lateinit var binaryPath: String
private var onFlashComplete: (() -> Unit)? = null private var onFlashComplete: (() -> Unit)? = null
private var originalSlot: String? = null
fun setOnFlashCompleteListener(listener: () -> Unit) { fun setOnFlashCompleteListener(listener: () -> Unit) {
onFlashComplete = listener onFlashComplete = listener
@@ -131,8 +132,30 @@ class HorizonKernelWorker(
state.updateStep(context.getString(R.string.horizon_flashing)) state.updateStep(context.getString(R.string.horizon_flashing))
state.updateProgress(0.7f) state.updateProgress(0.7f)
// 获取原始槽位信息
if (slot != null) {
state.updateStep(context.getString(R.string.horizon_getting_original_slot))
state.updateProgress(0.72f)
originalSlot = runCommandGetOutput(true, "getprop ro.boot.slot_suffix")
}
// 设置目标槽位
if (!slot.isNullOrEmpty()) {
state.updateStep(context.getString(R.string.horizon_setting_target_slot))
state.updateProgress(0.74f)
runCommand(true, "resetprop -n ro.boot.slot_suffix _$slot")
}
flash() flash()
// 恢复原始槽位
if (!originalSlot.isNullOrEmpty()) {
state.updateStep(context.getString(R.string.horizon_restoring_original_slot))
state.updateProgress(0.8f)
runCommand(true, "resetprop ro.boot.slot_suffix $originalSlot")
}
state.updateStep(context.getString(R.string.horizon_flash_complete_status)) state.updateStep(context.getString(R.string.horizon_flash_complete_status))
state.completeFlashing() state.completeFlashing()
@@ -141,6 +164,13 @@ class HorizonKernelWorker(
} }
} catch (e: Exception) { } catch (e: Exception) {
state.setError(e.message ?: context.getString(R.string.horizon_unknown_error)) state.setError(e.message ?: context.getString(R.string.horizon_unknown_error))
// 恢复原始槽位
if (!originalSlot.isNullOrEmpty()) {
state.updateStep(context.getString(R.string.horizon_restoring_original_slot))
state.updateProgress(0.8f)
runCommand(true, "resetprop ro.boot.slot_suffix $originalSlot")
}
} }
} }
@@ -245,12 +275,33 @@ class HorizonKernelWorker(
} }
} }
private fun runCommandGetOutput(su: Boolean, cmd: String): String {
val process = ProcessBuilder(if (su) "su" else "sh")
.redirectErrorStream(true)
.start()
return try {
process.outputStream.bufferedWriter().use { writer ->
writer.write("$cmd\n")
writer.write("exit\n")
writer.flush()
}
process.inputStream.bufferedReader().use { reader ->
reader.readText().trim()
}
} catch (_: Exception) {
""
} finally {
process.destroy()
}
}
private fun rootAvailable(): Boolean { private fun rootAvailable(): Boolean {
return try { return try {
val process = Runtime.getRuntime().exec("su -c id") val process = Runtime.getRuntime().exec("su -c id")
val exitValue = process.waitFor() val exitValue = process.waitFor()
exitValue == 0 exitValue == 0
} catch (e: Exception) { } catch (_: Exception) {
false false
} }
} }

View File

@@ -1,10 +1,12 @@
package com.sukisu.ultra.ui.component package com.sukisu.ultra.ui.component
import android.content.Context
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.material3.* import androidx.compose.material3.*
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -24,6 +26,20 @@ fun SlotSelectionDialog(
onDismiss: () -> Unit, onDismiss: () -> Unit,
onSlotSelected: (String) -> Unit onSlotSelected: (String) -> Unit
) { ) {
val context = LocalContext.current
var currentSlot by remember { mutableStateOf<String?>(null) }
var errorMessage by remember { mutableStateOf<String?>(null) }
LaunchedEffect(Unit) {
try {
currentSlot = getCurrentSlot(context)
errorMessage = null
} catch (e: Exception) {
errorMessage = e.message
currentSlot = null
}
}
if (show) { if (show) {
val cardColor = if (!ThemeConfig.useDynamicColor) { val cardColor = if (!ThemeConfig.useDynamicColor) {
ThemeConfig.currentTheme.ButtonContrast ThemeConfig.currentTheme.ButtonContrast
@@ -44,6 +60,27 @@ fun SlotSelectionDialog(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
if (errorMessage != null) {
Text(
text = "Error: $errorMessage",
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.error,
textAlign = TextAlign.Center
)
} else {
Text(
text = stringResource(
id = R.string.current_slot,
currentSlot ?: "Unknown"
),
style = MaterialTheme.typography.bodyMedium,
color = MaterialTheme.colorScheme.onSurfaceVariant,
textAlign = TextAlign.Center
)
}
Spacer(modifier = Modifier.height(12.dp))
Text( Text(
text = stringResource(id = R.string.select_slot_description), text = stringResource(id = R.string.select_slot_description),
style = MaterialTheme.typography.bodyMedium, style = MaterialTheme.typography.bodyMedium,
@@ -99,3 +136,24 @@ fun SlotSelectionDialog(
) )
} }
} }
// 获取当前槽位信息
private fun getCurrentSlot(context: Context): String? {
return runCommandGetOutput(true, "getprop ro.boot.slot_suffix")
}
private fun runCommandGetOutput(su: Boolean, cmd: String): String? {
return try {
val process = ProcessBuilder(if (su) "su" else "sh").start()
process.outputStream.bufferedWriter().use { writer ->
writer.write("$cmd\n")
writer.write("exit\n")
writer.flush()
}
process.inputStream.bufferedReader().use { reader ->
reader.readText().trim()
}
} catch (_: Exception) {
null
}
}

View File

@@ -287,4 +287,8 @@
<!-- 错误信息 --> <!-- 错误信息 -->
<string name="horizon_copy_failed">复制失败</string> <string name="horizon_copy_failed">复制失败</string>
<string name="horizon_unknown_error">未知错误</string> <string name="horizon_unknown_error">未知错误</string>
<string name="horizon_getting_original_slot">获取原有槽位</string>
<string name="horizon_setting_target_slot">设置指定槽位</string>
<string name="horizon_restoring_original_slot">恢复默认槽位</string>
<string name="current_slot">当前槽位:%1$s </string>
</resources> </resources>

View File

@@ -291,4 +291,8 @@
<!-- Error Messages --> <!-- Error Messages -->
<string name="horizon_copy_failed">Copy failed</string> <string name="horizon_copy_failed">Copy failed</string>
<string name="horizon_unknown_error">Unknown error</string> <string name="horizon_unknown_error">Unknown error</string>
<string name="horizon_getting_original_slot">Getting the original slot</string>
<string name="horizon_setting_target_slot">Setting the specified slot</string>
<string name="horizon_restoring_original_slot">Restore Default Slot</string>
<string name="current_slot">Current Slot%1$s </string>
</resources> </resources>