Android fixes and features

* Jit cache eviction (fixes out of memory errors in some games)

* Low power PPTC

* Fix 'unknown' games displayed when using game folder with subfolders

* Turn off NCE and PPTC by default
This commit is contained in:
KeatonTheBot
2025-06-02 21:47:55 -05:00
parent 3af88ad2e6
commit fda90239bc
58 changed files with 914 additions and 190 deletions
@@ -16,6 +16,8 @@ interface KenjinxNativeJna : Library {
vSyncMode: Int,
enableDockedMode: Boolean,
enablePptc: Boolean,
enableLowPowerPptc: Boolean,
enableJitCacheEviction: Boolean,
enableInternetAccess: Boolean,
enableFsIntegrityChecks: Boolean,
fsGlobalAccessLogMode: Int,
@@ -248,4 +248,24 @@ class MainActivity : BaseActivity() {
}
}
}
fun shutdownAndRestart() {
// Create an intent to restart the app
val packageManager = packageManager
val intent = packageManager.getLaunchIntentForPackage(packageName)
val componentName = intent?.component
val restartIntent = Intent.makeRestartActivityTask(componentName)
// Clean up resources if needed
mainViewModel?.let {
// Perform any critical cleanup
it.performanceManager?.setTurboMode(false)
}
// Start the new activity directly
startActivity(restartIntent)
// Force immediate process termination
Runtime.getRuntime().exit(0)
}
}
@@ -50,6 +50,10 @@ class GameModel(var file: DocumentFile, val context: Context) {
}
}
fun isUnknown() : Boolean {
return (titleName == "Unknown")
}
fun open(): Int {
descriptor = context.contentResolver.openFileDescriptor(file.uri, "rw")
@@ -107,6 +107,11 @@ class HomeViewModel(
for(game in loadedCache)
{
game.getGameInfo()
if(game.isUnknown())
{
loadedCache.remove(game);
}
}
} finally {
isLoading.value = false
@@ -179,6 +179,8 @@ class MainViewModel(val activity: MainActivity) {
settings.vSyncMode.ordinal,
settings.enableDocked,
settings.enablePptc,
settings.enableLowPowerPptc,
settings.enableJitCacheEviction,
false,
settings.enableFsIntegrityChecks,
settings.fsGlobalAccessLogMode,
@@ -285,6 +287,8 @@ class MainViewModel(val activity: MainActivity) {
settings.vSyncMode.ordinal,
settings.enableDocked,
settings.enablePptc,
settings.enableLowPowerPptc,
settings.enableJitCacheEviction,
false,
settings.enableFsIntegrityChecks,
settings.fsGlobalAccessLogMode,
@@ -7,6 +7,8 @@ import androidx.preference.PreferenceManager
class QuickSettings(val activity: Activity) {
var ignoreMissingServices: Boolean
var enablePptc: Boolean
var enableLowPowerPptc: Boolean
var enableJitCacheEviction: Boolean
var enableFsIntegrityChecks: Boolean
var fsGlobalAccessLogMode: Int
var enableDocked: Boolean
@@ -39,11 +41,13 @@ class QuickSettings(val activity: Activity) {
init {
memoryManagerMode = MemoryManagerMode.values()[sharedPref.getInt("memoryManagerMode", MemoryManagerMode.HostMappedUnsafe.ordinal)]
useNce = sharedPref.getBoolean("useNce", true)
useNce = sharedPref.getBoolean("useNce", false)
memoryConfiguration = MemoryConfiguration.values()[sharedPref.getInt("memoryConfiguration", MemoryConfiguration.MemoryConfiguration4GiB.ordinal)]
vSyncMode = VSyncMode.values()[sharedPref.getInt("vSyncMode", VSyncMode.Switch.ordinal)]
enableDocked = sharedPref.getBoolean("enableDocked", true)
enablePptc = sharedPref.getBoolean("enablePptc", true)
enableLowPowerPptc = sharedPref.getBoolean("enableLowPowerPptc", false)
enableJitCacheEviction = sharedPref.getBoolean("enableJitCacheEviction", true)
enableFsIntegrityChecks = sharedPref.getBoolean("enableFsIntegrityChecks", false)
fsGlobalAccessLogMode = sharedPref.getInt("fsGlobalAccessLogMode", 0)
ignoreMissingServices = sharedPref.getBoolean("ignoreMissingServices", false)
@@ -78,6 +82,8 @@ class QuickSettings(val activity: Activity) {
editor.putInt("vSyncMode", vSyncMode.ordinal)
editor.putBoolean("enableDocked", enableDocked)
editor.putBoolean("enablePptc", enablePptc)
editor.putBoolean("enableLowPowerPptc", enableLowPowerPptc)
editor.putBoolean("enableJitCacheEviction", enableJitCacheEviction)
editor.putBoolean("enableFsIntegrityChecks", enableFsIntegrityChecks)
editor.putInt("fsGlobalAccessLogMode", fsGlobalAccessLogMode)
editor.putBoolean("ignoreMissingServices", ignoreMissingServices)
@@ -31,14 +31,6 @@ class SettingsViewModel(val activity: MainActivity) {
sharedPref = getPreferences()
previousFolderCallback = activity.storageHelper!!.onFolderSelected
previousFileCallback = activity.storageHelper!!.onFileSelected
activity.storageHelper!!.onFolderSelected = { _, folder ->
run {
val p = folder.getAbsolutePath(activity)
val editor = sharedPref.edit()
editor?.putString("gameFolder", p)
editor?.apply()
}
}
}
private fun getPreferences(): SharedPreferences {
@@ -52,6 +44,8 @@ class SettingsViewModel(val activity: MainActivity) {
vSyncMode: MutableState<VSyncMode>,
enableDocked: MutableState<Boolean>,
enablePptc: MutableState<Boolean>,
enableLowPowerPptc: MutableState<Boolean>,
enableJitCacheEviction: MutableState<Boolean>,
enableFsIntegrityChecks: MutableState<Boolean>,
fsGlobalAccessLogMode: MutableState<Int>,
ignoreMissingServices: MutableState<Boolean>,
@@ -77,11 +71,13 @@ class SettingsViewModel(val activity: MainActivity) {
enableGraphicsLogs: MutableState<Boolean>
) {
memoryManagerMode.value = MemoryManagerMode.values()[sharedPref.getInt("memoryManagerMode", MemoryManagerMode.HostMappedUnsafe.ordinal)]
useNce.value = sharedPref.getBoolean("useNce", true)
useNce.value = sharedPref.getBoolean("useNce", false)
memoryConfiguration.value = MemoryConfiguration.values()[sharedPref.getInt("memoryConfiguration", MemoryConfiguration.MemoryConfiguration4GiB.ordinal)]
vSyncMode.value = VSyncMode.values()[sharedPref.getInt("vSyncMode", VSyncMode.Switch.ordinal)]
enableDocked.value = sharedPref.getBoolean("enableDocked", true)
enablePptc.value = sharedPref.getBoolean("enablePptc", true)
enableLowPowerPptc.value = sharedPref.getBoolean("enableLowPowerPptc", false)
enableJitCacheEviction.value = sharedPref.getBoolean("enableJitCacheEviction", false)
enableFsIntegrityChecks.value = sharedPref.getBoolean("enableFsIntegrityChecks", false)
fsGlobalAccessLogMode.value = sharedPref.getInt("fsGlobalAccessLogMode", 0)
ignoreMissingServices.value = sharedPref.getBoolean("ignoreMissingServices", false)
@@ -102,7 +98,7 @@ class SettingsViewModel(val activity: MainActivity) {
enableErrorLogs.value = sharedPref.getBoolean("enableErrorLogs", true)
enableGuestLogs.value = sharedPref.getBoolean("enableGuestLogs", true)
enableFsAccessLogs.value = sharedPref.getBoolean("enableFsAccessLogs", false)
enableTraceLogs.value = sharedPref.getBoolean("enableStubLogs", false)
enableTraceLogs.value = sharedPref.getBoolean("enableTraceLogs", false)
enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false)
enableGraphicsLogs.value = sharedPref.getBoolean("enableGraphicsLogs", false)
}
@@ -114,6 +110,8 @@ class SettingsViewModel(val activity: MainActivity) {
vSyncMode: MutableState<VSyncMode>,
enableDocked: MutableState<Boolean>,
enablePptc: MutableState<Boolean>,
enableLowPowerPptc: MutableState<Boolean>,
enableJitCacheEviction: MutableState<Boolean>,
enableFsIntegrityChecks: MutableState<Boolean>,
fsGlobalAccessLogMode: MutableState<Int>,
ignoreMissingServices: MutableState<Boolean>,
@@ -146,6 +144,8 @@ class SettingsViewModel(val activity: MainActivity) {
editor.putInt("vSyncMode", vSyncMode.value.ordinal)
editor.putBoolean("enableDocked", enableDocked.value)
editor.putBoolean("enablePptc", enablePptc.value)
editor.putBoolean("enableLowPowerPptc", enableLowPowerPptc.value)
editor.putBoolean("enableJitCacheEviction", enableJitCacheEviction.value)
editor.putBoolean("enableFsIntegrityChecks", enableFsIntegrityChecks.value)
editor.putInt("fsGlobalAccessLogMode", fsGlobalAccessLogMode.value)
editor.putBoolean("ignoreMissingServices", ignoreMissingServices.value)
@@ -171,7 +171,6 @@ class SettingsViewModel(val activity: MainActivity) {
editor.putBoolean("enableGraphicsLogs", enableGraphicsLogs.value)
editor.apply()
activity.storageHelper!!.onFolderSelected = previousFolderCallback
KenjinxNative.loggingSetEnabled(LogLevel.Info, enableInfoLogs.value)
KenjinxNative.loggingSetEnabled(LogLevel.Stub, enableStubLogs.value)
@@ -187,6 +186,15 @@ class SettingsViewModel(val activity: MainActivity) {
fun openGameFolder() {
val path = sharedPref.getString("gameFolder", "") ?: ""
activity.storageHelper!!.onFolderSelected = { _, folder ->
val p = folder.getAbsolutePath(activity)
val editor = sharedPref.edit()
editor.putString("gameFolder", p)
editor.apply()
activity.storageHelper!!.onFolderSelected = previousFolderCallback
activity.shutdownAndRestart()
}
if (path.isEmpty())
activity.storageHelper?.storage?.openFolderPicker()
else
@@ -197,22 +205,20 @@ class SettingsViewModel(val activity: MainActivity) {
}
fun selectKey(installState: MutableState<KeyInstallState>) {
if (installState.value != KeyInstallState.None)
if (installState.value != KeyInstallState.File)
return
activity.storageHelper!!.onFileSelected = { _, files ->
run {
activity.storageHelper!!.onFileSelected = previousFileCallback
val file = files.firstOrNull()
file?.apply {
if (name == "prod.keys") {
selectedKeyFile = file
installState.value = KeyInstallState.Query
}
else {
installState.value = KeyInstallState.Cancelled
}
val file = files.firstOrNull()
file?.apply {
if (name == "prod.keys") {
selectedKeyFile = file
installState.value = KeyInstallState.Query
} else {
installState.value = KeyInstallState.Cancelled
}
}
activity.storageHelper!!.onFileSelected = previousFileCallback
}
activity.storageHelper?.storage?.openFilePicker()
}
@@ -221,7 +227,7 @@ class SettingsViewModel(val activity: MainActivity) {
if (installState.value != KeyInstallState.Query)
return
if (selectedKeyFile == null) {
installState.value = KeyInstallState.None
installState.value = KeyInstallState.File
return
}
selectedKeyFile?.apply {
@@ -247,37 +253,35 @@ class SettingsViewModel(val activity: MainActivity) {
fun clearKeySelection(installState: MutableState<KeyInstallState>) {
selectedKeyFile = null
installState.value = KeyInstallState.None
installState.value = KeyInstallState.File
}
fun selectFirmware(installState: MutableState<FirmwareInstallState>) {
if (installState.value != FirmwareInstallState.None)
if (installState.value != FirmwareInstallState.File)
return
activity.storageHelper!!.onFileSelected = { _, files ->
run {
activity.storageHelper!!.onFileSelected = previousFileCallback
val file = files.firstOrNull()
file?.apply {
if (extension == "xci" || extension == "zip") {
installState.value = FirmwareInstallState.Verifying
thread {
Thread.sleep(1000)
val descriptor = activity.contentResolver.openFileDescriptor(file.uri, "rw")
descriptor?.use { d ->
selectedFirmwareVersion = KenjinxNative.deviceVerifyFirmware(d.fd, extension == "xci")
selectedFirmwareFile = file
if (!selectedFirmwareVersion.isEmpty()) {
installState.value = FirmwareInstallState.Query
} else {
installState.value = FirmwareInstallState.Cancelled
}
val file = files.firstOrNull()
file?.apply {
if (extension == "xci" || extension == "zip") {
installState.value = FirmwareInstallState.Verifying
thread {
val descriptor = activity.contentResolver.openFileDescriptor(file.uri, "rw")
descriptor?.use { d ->
selectedFirmwareVersion = KenjinxNative.deviceVerifyFirmware(d.fd, extension == "xci")
selectedFirmwareFile = file
if (!selectedFirmwareVersion.isEmpty()) {
installState.value = FirmwareInstallState.Query
} else {
installState.value = FirmwareInstallState.Cancelled
}
}
} else {
installState.value = FirmwareInstallState.Cancelled
}
} else {
installState.value = FirmwareInstallState.Cancelled
}
}
activity.storageHelper!!.onFileSelected = previousFileCallback
}
activity.storageHelper?.storage?.openFilePicker()
}
@@ -286,7 +290,7 @@ class SettingsViewModel(val activity: MainActivity) {
if (installState.value != FirmwareInstallState.Query)
return
if (selectedFirmwareFile == null) {
installState.value = FirmwareInstallState.None
installState.value = FirmwareInstallState.File
return
}
selectedFirmwareFile?.apply {
@@ -312,18 +316,18 @@ class SettingsViewModel(val activity: MainActivity) {
fun clearFirmwareSelection(installState: MutableState<FirmwareInstallState>) {
selectedFirmwareFile = null
selectedFirmwareVersion = ""
installState.value = FirmwareInstallState.None
installState.value = FirmwareInstallState.File
}
fun importAppData(
file: DocumentFile,
dataImportState: MutableState<DataImportState>
fun resetAppData(
dataResetState: MutableState<DataResetState>
) {
dataImportState.value = DataImportState.Import
try {
MainActivity.StorageHelper?.apply {
val stream = file.openInputStream(storage.context)
stream?.apply {
dataResetState.value = DataResetState.Reset
thread {
Thread.sleep(1000)
try {
MainActivity.StorageHelper?.apply {
val folders = listOf("bis", "games", "profiles", "system")
for (f in folders) {
val dir = File(MainActivity.AppPath + "${File.separator}${f}")
@@ -333,42 +337,73 @@ class SettingsViewModel(val activity: MainActivity) {
dir.mkdirs()
}
ZipInputStream(stream).use { zip ->
while (true) {
val header = zip.nextEntry ?: break
if (!folders.any { header.fileName.startsWith(it) }) {
continue
}
val filePath =
MainActivity.AppPath + File.separator + header.fileName
}
} finally {
dataResetState.value = DataResetState.Done
KenjinxNative.deviceReloadFilesystem()
MainActivity.mainViewModel?.refreshFirmwareVersion()
}
}
}
if (!header.isDirectory) {
val bos = BufferedOutputStream(FileOutputStream(filePath))
val bytesIn = ByteArray(4096)
var read: Int = 0
while (zip.read(bytesIn).also { read = it } > 0) {
bos.write(bytesIn, 0, read)
fun importAppData(
file: DocumentFile,
dataImportState: MutableState<DataImportState>
) {
dataImportState.value = DataImportState.Import
thread {
Thread.sleep(1000)
try {
MainActivity.StorageHelper?.apply {
val stream = file.openInputStream(storage.context)
stream?.apply {
val folders = listOf("bis", "games", "profiles", "system")
for (f in folders) {
val dir = File(MainActivity.AppPath + "${File.separator}${f}")
if (dir.exists()) {
dir.deleteRecursively()
}
dir.mkdirs()
}
ZipInputStream(stream).use { zip ->
while (true) {
val header = zip.nextEntry ?: break
if (!folders.any { header.fileName.startsWith(it) }) {
continue
}
val filePath =
MainActivity.AppPath + File.separator + header.fileName
if (!header.isDirectory) {
val bos = BufferedOutputStream(FileOutputStream(filePath))
val bytesIn = ByteArray(4096)
var read: Int = 0
while (zip.read(bytesIn).also { read = it } > 0) {
bos.write(bytesIn, 0, read)
}
bos.close()
} else {
val dir = File(filePath)
dir.mkdir()
}
bos.close()
} else {
val dir = File(filePath)
dir.mkdir()
}
}
stream.close()
}
stream.close()
}
} finally {
dataImportState.value = DataImportState.Done
KenjinxNative.deviceReloadFilesystem()
MainActivity.mainViewModel?.refreshFirmwareVersion()
}
} finally {
dataImportState.value = DataImportState.Done
KenjinxNative.deviceReloadFilesystem()
MainActivity.mainViewModel?.refreshFirmwareVersion()
}
}
}
enum class KeyInstallState {
None,
File,
Cancelled,
Query,
Install,
@@ -376,7 +411,7 @@ enum class KeyInstallState {
}
enum class FirmwareInstallState {
None,
File,
Cancelled,
Verifying,
Query,
@@ -384,8 +419,14 @@ enum class FirmwareInstallState {
Done
}
enum class DataResetState {
Query,
Reset,
Done
}
enum class DataImportState {
None,
File,
Query,
Import,
Done
@@ -22,6 +22,7 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.Build
import androidx.compose.material.icons.filled.Create
import androidx.compose.material.icons.filled.FileDownload
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.MailOutline
@@ -62,6 +63,7 @@ import kotlin.concurrent.thread
import org.kenjinx.android.MainActivity
import org.kenjinx.android.providers.DocumentProvider
import org.kenjinx.android.viewmodels.DataImportState
import org.kenjinx.android.viewmodels.DataResetState
import org.kenjinx.android.viewmodels.FirmwareInstallState
import org.kenjinx.android.viewmodels.KeyInstallState
import org.kenjinx.android.viewmodels.MainViewModel
@@ -90,6 +92,8 @@ class SettingViews {
val vSyncMode = remember { mutableStateOf(VSyncMode.Switch) }
val enableDocked = remember { mutableStateOf(false) }
val enablePptc = remember { mutableStateOf(false) }
val enableLowPowerPptc = remember { mutableStateOf(false) }
val enableJitCacheEviction = remember { mutableStateOf(false) }
var enableFsIntegrityChecks = remember { mutableStateOf(false) }
var fsGlobalAccessLogMode = remember { mutableStateOf(0) }
val ignoreMissingServices = remember { mutableStateOf(false) }
@@ -100,12 +104,14 @@ class SettingViews {
val maxAnisotropy = remember { mutableStateOf(0f) }
val useVirtualController = remember { mutableStateOf(true) }
val showKeyDialog = remember { mutableStateOf(false) }
val keyInstallState = remember { mutableStateOf(KeyInstallState.None) }
val keyInstallState = remember { mutableStateOf(KeyInstallState.File) }
val showFirwmareDialog = remember { mutableStateOf(false) }
val firmwareInstallState = remember { mutableStateOf(FirmwareInstallState.None) }
val firmwareInstallState = remember { mutableStateOf(FirmwareInstallState.File) }
val firmwareVersion = remember { mutableStateOf(mainViewModel.firmwareVersion) }
val showDataResetDialog = remember { mutableStateOf(false) }
val showDataImportDialog = remember { mutableStateOf(false) }
val dataImportState = remember { mutableStateOf(DataImportState.None) }
val dataResetState = remember { mutableStateOf(DataResetState.Query) }
val dataImportState = remember { mutableStateOf(DataImportState.File) }
var dataFile = remember { mutableStateOf<DocumentFile?>(null) }
val isGrid = remember { mutableStateOf(true) }
val useSwitchLayout = remember { mutableStateOf(true) }
@@ -131,6 +137,8 @@ class SettingViews {
vSyncMode,
enableDocked,
enablePptc,
enableLowPowerPptc,
enableJitCacheEviction,
enableFsIntegrityChecks,
fsGlobalAccessLogMode,
ignoreMissingServices,
@@ -172,6 +180,8 @@ class SettingViews {
vSyncMode,
enableDocked,
enablePptc,
enableLowPowerPptc,
enableJitCacheEviction,
enableFsIntegrityChecks,
fsGlobalAccessLogMode,
ignoreMissingServices,
@@ -236,23 +246,6 @@ class SettingViews {
modifier = Modifier.align(Alignment.CenterVertically)
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.padding(horizontal = 8.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
){
ActionButton(
onClick = {
settingsViewModel.openGameFolder()
},
text = "Add Game Folder",
icon = Icons.Default.Add,
modifier = Modifier.weight(1f),
isFullWidth = false,
)
}
Row(
modifier = Modifier
.fillMaxWidth()
@@ -287,7 +280,40 @@ class SettingViews {
isFullWidth = false,
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.padding(horizontal = 8.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
){
ActionButton(
onClick = {
settingsViewModel.openGameFolder()
},
text = "Add Game Folder",
icon = Icons.Default.Add,
modifier = Modifier.weight(1f),
isFullWidth = false,
)
}
Row(
modifier = Modifier
.fillMaxWidth()
.height(56.dp)
.padding(horizontal = 8.dp, vertical = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween,
) {
ActionButton(
onClick = {
showDataResetDialog.value = true
},
text = "Reinit App Data",
icon = Icons.Default.Create,
modifier = Modifier.weight(1f),
isFullWidth = false,
)
}
Row(
modifier = Modifier
.fillMaxWidth()
@@ -359,6 +385,7 @@ class SettingViews {
if (keyInstallState.value != KeyInstallState.Install) {
showKeyDialog.value = false
settingsViewModel.clearKeySelection(keyInstallState)
keyInstallState.value = KeyInstallState.File
}
}
) {
@@ -378,7 +405,7 @@ class SettingViews {
)
when (keyInstallState.value) {
KeyInstallState.None -> {
KeyInstallState.File -> {
Text(
text = "Select a key file to install key from.",
modifier = Modifier
@@ -437,7 +464,7 @@ class SettingViews {
keyInstallState
)
if (keyInstallState.value == KeyInstallState.None) {
if (keyInstallState.value == KeyInstallState.File) {
showKeyDialog.value = false
settingsViewModel.clearKeySelection(keyInstallState)
}
@@ -561,6 +588,7 @@ class SettingViews {
if (firmwareInstallState.value != FirmwareInstallState.Install) {
showFirwmareDialog.value = false
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
firmwareInstallState.value = FirmwareInstallState.File
}
}
) {
@@ -580,7 +608,7 @@ class SettingViews {
)
when (firmwareInstallState.value) {
FirmwareInstallState.None -> {
FirmwareInstallState.File -> {
Text(
text = "Select a zip or xci file to install firmware from.",
modifier = Modifier
@@ -635,7 +663,7 @@ class SettingViews {
onClick = {
settingsViewModel.installFirmware(firmwareInstallState)
if (firmwareInstallState.value == FirmwareInstallState.None) {
if (firmwareInstallState.value == FirmwareInstallState.File) {
showFirwmareDialog.value = false
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
}
@@ -779,13 +807,125 @@ class SettingViews {
}
}
}
SimpleAlertDialog.Custom(
showDialog = showDataResetDialog,
onDismissRequest = {
if (dataResetState.value != DataResetState.Reset) {
showDataResetDialog.value = false
dataResetState.value = DataResetState.Query
}
}
) {
Column(
modifier = Modifier
.padding(16.dp)
.fillMaxWidth(),
verticalArrangement = Arrangement.SpaceBetween,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "App Data Reinit",
modifier = Modifier
.fillMaxWidth()
.padding(bottom = 16.dp),
textAlign = TextAlign.Center
)
when (dataResetState.value) {
DataResetState.Query -> {
Text(
text = "Current bis, games, profiles and system folders will be reset. Do you want to continue?",
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, bottom = 8.dp),
textAlign = TextAlign.Start
)
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp)
) {
Button(
onClick = {
thread {
settingsViewModel.resetAppData(dataResetState)
}
},
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
Text(text = "Yes")
}
Button(
onClick = {
showDataResetDialog.value = false
},
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
Text(text = "No")
}
}
}
DataResetState.Reset -> {
Text(
text = "Resetting app data...",
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, bottom = 8.dp),
textAlign = TextAlign.Start
)
LinearProgressIndicator(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp)
)
}
DataResetState.Done -> {
Text(
text = "Data reset completed successfully.",
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, bottom = 8.dp),
textAlign = TextAlign.Start
)
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp)
) {
Button(
onClick = {
showDataResetDialog.value = false
firmwareVersion.value = mainViewModel.firmwareVersion
dataResetState.value = DataResetState.Query
mainViewModel.userViewModel.refreshUsers()
mainViewModel.homeViewModel.requestReload()
mainViewModel.activity.shutdownAndRestart()
},
modifier = Modifier
.weight(1f)
.padding(horizontal = 8.dp)
) {
Text(text = "Close")
}
}
}
}
}
}
SimpleAlertDialog.Custom(
showDialog = showDataImportDialog,
onDismissRequest = {
if (dataImportState.value != DataImportState.Import) {
showDataImportDialog.value = false
dataFile.value = null
dataImportState.value = DataImportState.None
dataImportState.value = DataImportState.File
}
}
) {
@@ -805,9 +945,9 @@ class SettingViews {
)
when (dataImportState.value) {
DataImportState.None -> {
DataImportState.File -> {
Text(
text = "Select a zip file to import app data from.",
text = "Select a zip file to import bis, games, profiles and system folders from another Android installation.",
modifier = Modifier
.fillMaxWidth()
.padding(start = 8.dp, bottom = 8.dp),
@@ -854,7 +994,7 @@ class SettingViews {
onClick = {
showDataImportDialog.value = false
dataFile.value = null
dataImportState.value = DataImportState.None
dataImportState.value = DataImportState.File
},
modifier = Modifier
.weight(1f)
@@ -942,9 +1082,10 @@ class SettingViews {
showDataImportDialog.value = false
dataFile.value = null
firmwareVersion.value = mainViewModel.firmwareVersion
dataImportState.value = DataImportState.None
dataImportState.value = DataImportState.File
mainViewModel.userViewModel.refreshUsers()
mainViewModel.homeViewModel.requestReload()
mainViewModel.activity.shutdownAndRestart()
},
modifier = Modifier
.weight(1f)
@@ -1032,6 +1173,8 @@ class SettingViews {
Column(modifier = Modifier.fillMaxWidth()) {
useNce.SwitchSelector(label = "Enable NCE (Native Code Execution)")
enablePptc.SwitchSelector(label = "Enable PPTC (Profiled Persistent Translation Cache)")
enableLowPowerPptc.SwitchSelector(label = "Enable Low-Power PPTC")
enableJitCacheEviction.SwitchSelector(label = "Enable Jit Cache Eviction")
MemoryModeDropdown(
selectedMemoryManagerMode = memoryManagerMode.value,
onModeSelected = { mode ->