mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2025-07-20 15:15:46 +00:00
[frontend] Firmware setup & requirement (#222)
Currently Android only, will need to be added to desktop. Android incorrectly records firmware as 19.0.1 if on a higher version... TODO: - [x] desktop - [x] fix android Signed-off-by: crueter <swurl@swurl.xyz> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/222 Co-authored-by: crueter <swurl@swurl.xyz> Co-committed-by: crueter <swurl@swurl.xyz>
This commit is contained in:
parent
20bf141faa
commit
f121df0aa3
22 changed files with 379 additions and 74 deletions
|
@ -246,6 +246,7 @@ dependencies {
|
|||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||
implementation("androidx.compose.ui:ui-graphics-android:1.7.8")
|
||||
implementation("androidx.compose.ui:ui-text-android:1.7.8")
|
||||
implementation("net.swiftzer.semver:semver:2.0.0")
|
||||
}
|
||||
|
||||
fun runGitCommand(command: List<String>): String {
|
||||
|
|
|
@ -16,6 +16,7 @@ import android.view.View
|
|||
import android.widget.TextView
|
||||
import androidx.annotation.Keep
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import net.swiftzer.semver.SemVer
|
||||
import java.lang.ref.WeakReference
|
||||
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||
import org.yuzu.yuzu_emu.fragments.CoreErrorDialogFragment
|
||||
|
@ -407,6 +408,26 @@ object NativeLibrary {
|
|||
*/
|
||||
external fun isFirmwareAvailable(): Boolean
|
||||
|
||||
/**
|
||||
* Gets the firmware version.
|
||||
*
|
||||
* @return Reported firmware version
|
||||
*/
|
||||
external fun firmwareVersion(): String
|
||||
|
||||
fun isFirmwareSupported(): Boolean {
|
||||
var version: SemVer
|
||||
|
||||
try {
|
||||
version = SemVer.parse(firmwareVersion())
|
||||
} catch (_: Exception) {
|
||||
return false
|
||||
}
|
||||
val max = SemVer(19, 0, 1)
|
||||
|
||||
return version <= max
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the PatchManager for any addons that are available
|
||||
*
|
||||
|
|
|
@ -41,6 +41,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
|||
SHOW_DEVICE_MODEL("show_device_model"),
|
||||
SHOW_GPU_MODEL("show_gpu_model"),
|
||||
SHOW_SOC_MODEL("show_soc_model"),
|
||||
SHOW_FW_VERSION("show_firmware_version"),
|
||||
|
||||
SOC_OVERLAY_BACKGROUND("soc_overlay_background"),
|
||||
|
||||
|
|
|
@ -460,6 +460,14 @@ abstract class SettingsItem(
|
|||
descriptionId = R.string.show_soc_model_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.SHOW_FW_VERSION,
|
||||
titleId = R.string.show_fw_version,
|
||||
descriptionId = R.string.show_fw_version_description
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
|
|
|
@ -271,6 +271,8 @@ class SettingsFragmentPresenter(
|
|||
if (Build.VERSION.SDK_INT >= 31) {
|
||||
add(BooleanSetting.SHOW_SOC_MODEL.key)
|
||||
}
|
||||
|
||||
add(BooleanSetting.SHOW_FW_VERSION.key)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
|
@ -754,6 +753,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
if (BooleanSetting.SHOW_FW_VERSION.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
|
||||
if (sb.isNotEmpty()) sb.append(" | ")
|
||||
sb.append(NativeLibrary.firmwareVersion())
|
||||
}
|
||||
|
||||
binding.showSocOverlayText.text = sb.toString()
|
||||
|
||||
if (BooleanSetting.SOC_OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
@ -137,7 +137,7 @@ class HomeSettingsFragment : Fragment() {
|
|||
binding.root.findNavController()
|
||||
.navigate(R.id.action_homeSettingsFragment_to_appletLauncherFragment)
|
||||
},
|
||||
{ NativeLibrary.isFirmwareAvailable() },
|
||||
{ NativeLibrary.isFirmwareAvailable() && NativeLibrary.isFirmwareSupported() },
|
||||
R.string.applets_error_firmware,
|
||||
R.string.applets_error_description
|
||||
)
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
|
@ -28,6 +32,8 @@ class ProgressDialogFragment : DialogFragment() {
|
|||
|
||||
private val PROGRESS_BAR_RESOLUTION = 1000
|
||||
|
||||
var onDialogComplete: (() -> Unit)? = null
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val titleId = requireArguments().getInt(TITLE)
|
||||
val cancellable = requireArguments().getBoolean(CANCELLABLE)
|
||||
|
@ -121,6 +127,11 @@ class ProgressDialogFragment : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
override fun onDismiss(dialog: DialogInterface) {
|
||||
super.onDismiss(dialog)
|
||||
onDialogComplete?.invoke()
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TAG = "IndeterminateProgressDialogFragment"
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
|
@ -129,7 +129,7 @@ class SetupFragment : Fragment() {
|
|||
0,
|
||||
{
|
||||
if (NotificationManagerCompat.from(requireContext())
|
||||
.areNotificationsEnabled()
|
||||
.areNotificationsEnabled()
|
||||
) {
|
||||
StepState.COMPLETE
|
||||
} else {
|
||||
|
@ -166,6 +166,32 @@ class SetupFragment : Fragment() {
|
|||
}
|
||||
)
|
||||
)
|
||||
add(
|
||||
SetupPage(
|
||||
R.drawable.ic_firmware,
|
||||
R.string.firmware,
|
||||
R.string.firmware_description,
|
||||
R.drawable.ic_add,
|
||||
true,
|
||||
R.string.select_firmware,
|
||||
{
|
||||
firmwareCallback = it
|
||||
getFirmware.launch(arrayOf("application/zip"))
|
||||
},
|
||||
true,
|
||||
R.string.install_firmware_warning,
|
||||
R.string.install_firmware_warning_description,
|
||||
R.string.install_firmware_warning_help,
|
||||
{
|
||||
if (NativeLibrary.isFirmwareAvailable()) {
|
||||
StepState.COMPLETE
|
||||
} else {
|
||||
StepState.INCOMPLETE
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
add(
|
||||
SetupPage(
|
||||
R.drawable.ic_controller,
|
||||
|
@ -321,6 +347,7 @@ class SetupFragment : Fragment() {
|
|||
}
|
||||
|
||||
private lateinit var keyCallback: SetupCallback
|
||||
private lateinit var firmwareCallback: SetupCallback
|
||||
|
||||
val getProdKey =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||
|
@ -332,6 +359,17 @@ class SetupFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
val getFirmware =
|
||||
registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
|
||||
if (result != null) {
|
||||
mainActivity.processFirmware(result) {
|
||||
if (NativeLibrary.isFirmwareAvailable()) {
|
||||
firmwareCallback.onStepCompleted()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var gamesDirCallback: SetupCallback
|
||||
|
||||
val getGamesDirectory =
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.model
|
||||
|
@ -31,6 +31,9 @@ class HomeViewModel : ViewModel() {
|
|||
private val _checkKeys = MutableStateFlow(false)
|
||||
val checkKeys = _checkKeys.asStateFlow()
|
||||
|
||||
private val _checkFirmware = MutableStateFlow(false)
|
||||
val checkFirmware = _checkFirmware.asStateFlow()
|
||||
|
||||
var navigatedToSetup = false
|
||||
|
||||
fun setStatusBarShadeVisibility(visible: Boolean) {
|
||||
|
@ -63,4 +66,8 @@ class HomeViewModel : ViewModel() {
|
|||
fun setCheckKeys(value: Boolean) {
|
||||
_checkKeys.value = value
|
||||
}
|
||||
|
||||
fun setCheckFirmware(value: Boolean) {
|
||||
_checkFirmware.value = value
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.ui.main
|
||||
|
@ -62,6 +62,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
private val CHECKED_DECRYPTION = "CheckedDecryption"
|
||||
private var checkedDecryption = false
|
||||
|
||||
private val CHECKED_FIRMWARE = "CheckedFirmware"
|
||||
private var checkedFirmware = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
val splashScreen = installSplashScreen()
|
||||
splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
|
||||
|
@ -76,17 +79,27 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
|
||||
if (savedInstanceState != null) {
|
||||
checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION)
|
||||
checkedFirmware = savedInstanceState.getBoolean(CHECKED_FIRMWARE)
|
||||
}
|
||||
if (!checkedDecryption) {
|
||||
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
|
||||
if (!firstTimeSetup) {
|
||||
checkKeys()
|
||||
showPreAlphaWarningDialog()
|
||||
}
|
||||
checkedDecryption = true
|
||||
}
|
||||
|
||||
if (!checkedFirmware) {
|
||||
val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
|
||||
.getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
|
||||
if (!firstTimeSetup) {
|
||||
checkFirmware()
|
||||
showPreAlphaWarningDialog()
|
||||
}
|
||||
checkedFirmware = true
|
||||
}
|
||||
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
|
||||
|
||||
|
@ -135,6 +148,10 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
if (it) checkKeys()
|
||||
}
|
||||
|
||||
homeViewModel.checkFirmware.collect(this, resetState = { homeViewModel.setCheckFirmware(false) }) {
|
||||
if (it) checkFirmware()
|
||||
}
|
||||
|
||||
setInsets()
|
||||
}
|
||||
|
||||
|
@ -175,9 +192,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
}
|
||||
}
|
||||
|
||||
private fun checkFirmware() {
|
||||
if (!NativeLibrary.isFirmwareAvailable() || !NativeLibrary.isFirmwareSupported()) {
|
||||
MessageDialogFragment.newInstance(
|
||||
titleId = R.string.firmware_missing,
|
||||
descriptionId = R.string.firmware_missing_description,
|
||||
helpLinkId = R.string.firmware_missing_help
|
||||
).show(supportFragmentManager, MessageDialogFragment.TAG)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
|
||||
outState.putBoolean(CHECKED_FIRMWARE, checkedFirmware)
|
||||
}
|
||||
|
||||
fun finishSetup(navController: NavController) {
|
||||
|
@ -306,6 +335,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
homeViewModel.setCheckKeys(true)
|
||||
homeViewModel.setCheckFirmware(true)
|
||||
gamesViewModel.reloadGames(true)
|
||||
return true
|
||||
} else {
|
||||
|
@ -327,47 +357,55 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
|
||||
|
||||
val firmwarePath =
|
||||
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
|
||||
|
||||
ProgressDialogFragment.newInstance(
|
||||
this,
|
||||
R.string.firmware_installing
|
||||
) { progressCallback, _ ->
|
||||
var messageToShow: Any
|
||||
try {
|
||||
FileUtil.unzipToInternalStorage(
|
||||
result.toString(),
|
||||
cacheFirmwareDir,
|
||||
progressCallback
|
||||
)
|
||||
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
|
||||
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
|
||||
messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) {
|
||||
MessageDialogFragment.newInstance(
|
||||
this,
|
||||
titleId = R.string.firmware_installed_failure,
|
||||
descriptionId = R.string.firmware_installed_failure_description
|
||||
)
|
||||
} else {
|
||||
firmwarePath.deleteRecursively()
|
||||
cacheFirmwareDir.copyRecursively(firmwarePath, true)
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
getString(R.string.save_file_imported_success)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.error("[MainActivity] Firmware install failed - ${e.message}")
|
||||
messageToShow = getString(R.string.fatal_error)
|
||||
} finally {
|
||||
cacheFirmwareDir.deleteRecursively()
|
||||
}
|
||||
messageToShow
|
||||
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
|
||||
processFirmware(result)
|
||||
}
|
||||
|
||||
fun processFirmware(result: Uri, onComplete: (() -> Unit)? = null) {
|
||||
val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") }
|
||||
|
||||
val firmwarePath =
|
||||
File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||
val cacheFirmwareDir = File("${cacheDir.path}/registered/")
|
||||
|
||||
ProgressDialogFragment.newInstance(
|
||||
this,
|
||||
R.string.firmware_installing
|
||||
) { progressCallback, _ ->
|
||||
var messageToShow: Any
|
||||
try {
|
||||
FileUtil.unzipToInternalStorage(
|
||||
result.toString(),
|
||||
cacheFirmwareDir,
|
||||
progressCallback
|
||||
)
|
||||
val unfilteredNumOfFiles = cacheFirmwareDir.list()?.size ?: -1
|
||||
val filteredNumOfFiles = cacheFirmwareDir.list(filterNCA)?.size ?: -2
|
||||
messageToShow = if (unfilteredNumOfFiles != filteredNumOfFiles) {
|
||||
MessageDialogFragment.newInstance(
|
||||
this,
|
||||
titleId = R.string.firmware_installed_failure,
|
||||
descriptionId = R.string.firmware_installed_failure_description
|
||||
)
|
||||
} else {
|
||||
firmwarePath.deleteRecursively()
|
||||
cacheFirmwareDir.copyRecursively(firmwarePath, true)
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
homeViewModel.setCheckFirmware(true)
|
||||
getString(R.string.save_file_imported_success)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.error("[MainActivity] Firmware install failed - ${e.message}")
|
||||
messageToShow = getString(R.string.fatal_error)
|
||||
} finally {
|
||||
cacheFirmwareDir.deleteRecursively()
|
||||
}
|
||||
messageToShow
|
||||
}.apply {
|
||||
onDialogComplete = onComplete
|
||||
}.show(supportFragmentManager, ProgressDialogFragment.TAG)
|
||||
}
|
||||
|
||||
fun uninstallFirmware() {
|
||||
val firmwarePath = File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/")
|
||||
ProgressDialogFragment.newInstance(
|
||||
|
@ -382,6 +420,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
|
|||
// Optionally reinitialize the system or perform other necessary steps
|
||||
NativeLibrary.initializeSystem(true)
|
||||
homeViewModel.setCheckKeys(true)
|
||||
homeViewModel.setCheckFirmware(true)
|
||||
messageToShow = getString(R.string.firmware_uninstalled_success)
|
||||
} else {
|
||||
messageToShow = getString(R.string.firmware_uninstalled_failure)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -136,6 +139,11 @@ namespace AndroidSettings {
|
|||
Settings::Specialization::Default, true, true,
|
||||
&show_performance_overlay};
|
||||
|
||||
Settings::Setting<bool> show_fw_version{linkage, true, "show_firmware_version",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true, true,
|
||||
&show_performance_overlay};
|
||||
|
||||
Settings::Setting<bool> soc_overlay_background{linkage, false, "soc_overlay_background",
|
||||
Settings::Category::Overlay,
|
||||
Settings::Specialization::Default, true, true,
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/set/system_settings_server.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "frontend_common/config.h"
|
||||
#include "hid_core/frontend/emulated_controller.h"
|
||||
|
@ -762,22 +763,47 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setCabinetMode(JNIEnv* env, jclass cl
|
|||
static_cast<Service::NFP::CabinetMode>(jcabinetMode));
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, jclass clazz) {
|
||||
bool isFirmwarePresent() {
|
||||
auto bis_system =
|
||||
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
|
||||
EmulationSession::GetInstance().System().GetFileSystemController().GetSystemNANDContents();
|
||||
if (!bis_system) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Query an applet to see if it's available
|
||||
auto applet_nca =
|
||||
bis_system->GetEntry(0x010000000000100Dull, FileSys::ContentRecordType::Program);
|
||||
bis_system->GetEntry(0x010000000000100Dull, FileSys::ContentRecordType::Program);
|
||||
if (!applet_nca) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isFirmwareAvailable(JNIEnv* env, jclass clazz) {
|
||||
return isFirmwarePresent();
|
||||
}
|
||||
|
||||
// TODO(crueter): This check is nonfunctional...
|
||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_firmwareVersion(JNIEnv* env, jclass clazz) {
|
||||
Service::Set::FirmwareVersionFormat firmware_data{};
|
||||
const auto result = Service::Set::GetFirmwareVersionImpl(
|
||||
firmware_data, EmulationSession::GetInstance().System(),
|
||||
Service::Set::GetFirmwareVersionType::Version2);
|
||||
|
||||
if (result.IsError() || !isFirmwarePresent()) {
|
||||
LOG_INFO(Frontend, "Installed firmware: No firmware available");
|
||||
|
||||
return Common::Android::ToJString(env, "N/A");
|
||||
}
|
||||
|
||||
const std::string display_version(firmware_data.display_version.data());
|
||||
const std::string display_title(firmware_data.display_title.data());
|
||||
|
||||
LOG_INFO(Frontend, "Installed firmware: {}", display_title);
|
||||
|
||||
return Common::Android::ToJString(env, display_version);
|
||||
}
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env, jobject jobj,
|
||||
jstring jpath,
|
||||
jstring jprogramId) {
|
||||
|
|
|
@ -58,6 +58,8 @@
|
|||
<string name="show_gpu_model_description">Display the host GPU model</string>
|
||||
<string name="show_soc_model">Show SoC Model</string>
|
||||
<string name="show_soc_model_description">Display the host SoC model</string>
|
||||
<string name="show_fw_version">Show Firmware Version</string>
|
||||
<string name="show_fw_version_description">Display the installed firmware version</string>
|
||||
|
||||
<!-- Eden`s Veil -->
|
||||
<string name="eden_veil">Eden’s Veil</string>
|
||||
|
@ -220,6 +222,9 @@
|
|||
<string name="keys">Keys</string>
|
||||
<string name="keys_description">Select your <b>prod.keys</b> file with the button below.</string>
|
||||
<string name="select_keys">Select Keys</string>
|
||||
<string name="firmware">Firmware</string>
|
||||
<string name="firmware_description">Select your <b>firmware.zip</b> file with the button below.\nEden currently requires version <b>19.0.1</b> or below.</string>
|
||||
<string name="select_firmware">Select Firmware</string>
|
||||
<string name="games">Games</string>
|
||||
<string name="games_description">Select your <b>Games</b> folder with the button below.</string>
|
||||
<string name="done">Done</string>
|
||||
|
@ -232,6 +237,8 @@
|
|||
<string name="step_complete">Complete!</string>
|
||||
|
||||
<!-- Home strings -->
|
||||
<string name="firmware_version">Firmware:</string>
|
||||
|
||||
<string name="alphabetical">Alphabetical</string>
|
||||
<string name="view_list">List</string>
|
||||
<string name="view_grid">Grid</string>
|
||||
|
@ -262,6 +269,9 @@
|
|||
<string name="install_prod_keys_warning">Skip adding keys?</string>
|
||||
<string name="install_prod_keys_warning_description">Valid keys are required to emulate retail games. Only homebrew apps will function if you continue.</string>
|
||||
<string name="install_prod_keys_warning_help">https://yuzu-mirror.github.io/help/quickstart/#guide-introduction</string>
|
||||
<string name="install_firmware_warning">Skip adding firmware?</string>
|
||||
<string name="install_firmware_warning_description">Many games require access to firmware to run properly.</string>
|
||||
<string name="install_firmware_warning_help">https://yuzu-mirror.github.io/help/quickstart/#guide-introduction</string>
|
||||
<string name="notifications">Notifications</string>
|
||||
<string name="notifications_description">Grant the notification permission with the button below.</string>
|
||||
<string name="give_permission">Grant permission</string>
|
||||
|
@ -357,18 +367,24 @@
|
|||
<string name="no_save_data_found">No save data found</string>
|
||||
<string name="verify_installed_content">Verify installed content</string>
|
||||
<string name="verify_installed_content_description">Checks all installed content for corruption</string>
|
||||
|
||||
<string name="keys_missing">Encryption keys are missing</string>
|
||||
<string name="keys_missing_description">Firmware and retail games cannot be decrypted</string>
|
||||
<string name="keys_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-decryption-keys</string>
|
||||
|
||||
<string name="firmware_missing">Firmware is missing or too new</string>
|
||||
<string name="firmware_missing_description">Some games may not function properly. Eden requires firmware 19.0.1 or below.</string>
|
||||
<string name="firmware_missing_help">https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware</string>
|
||||
|
||||
<!-- Applet launcher strings -->
|
||||
<string name="qlaunch_applet">Qlaunch</string>
|
||||
<string name="qlaunch_description">Launch applications from the system home screen</string>
|
||||
<string name="applets">Applet launcher</string>
|
||||
<string name="applets_description">Launch system applets using installed firmware</string>
|
||||
<string name="applets_error_firmware">Firmware not installed</string>
|
||||
<string name="applets_error_firmware">Firmware not installed or invalid version</string>
|
||||
<string name="applets_error_applet">Applet not available</string>
|
||||
<string name="applets_error_description"><![CDATA[Please ensure your <a href="https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file and <a href="https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware">firmware</a> are installed and try again.]]></string>
|
||||
<string name="applets_error_description"><![CDATA[Please ensure your <a href="https://yuzu-mirror.github.io/help/quickstart/#dumping-prodkeys-and-titlekeys">prod.keys</a> file and
|
||||
<a href="https://yuzu-mirror.github.io/help/quickstart/#dumping-system-firmware">firmware</a> are installed and try again.<br>Additionally, ensure your firmware is of version 19.0.1 or older.]]></string>
|
||||
<string name="album_applet">Album</string>
|
||||
<string name="album_applet_description">See images stored in the user screenshots folder with the system photo viewer</string>
|
||||
<string name="mii_edit_applet">Mii edit</string>
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -11,8 +14,8 @@ namespace HLE::ApiVersion {
|
|||
|
||||
// Horizon OS version constants.
|
||||
|
||||
constexpr u8 HOS_VERSION_MAJOR = 19;
|
||||
constexpr u8 HOS_VERSION_MINOR = 0;
|
||||
constexpr u8 HOS_VERSION_MAJOR = 20;
|
||||
constexpr u8 HOS_VERSION_MINOR = 1;
|
||||
constexpr u8 HOS_VERSION_MICRO = 1;
|
||||
|
||||
// NintendoSDK version constants.
|
||||
|
@ -21,15 +24,15 @@ constexpr u8 SDK_REVISION_MAJOR = 1;
|
|||
constexpr u8 SDK_REVISION_MINOR = 0;
|
||||
|
||||
constexpr char PLATFORM_STRING[] = "NX";
|
||||
constexpr char VERSION_HASH[] = "835c78223df116284ef7e36e8441760edc81729c";
|
||||
constexpr char DISPLAY_VERSION[] = "19.0.1";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 19.0.1-1.0";
|
||||
constexpr char VERSION_HASH[] = "9ffad64d79dd150490201461bdf66c8db963f57d";
|
||||
constexpr char DISPLAY_VERSION[] = "20.1.1";
|
||||
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 20.1.1-1.0";
|
||||
|
||||
// Atmosphere version constants.
|
||||
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MAJOR = 1;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 0;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 0;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MINOR = 9;
|
||||
constexpr u8 ATMOSPHERE_RELEASE_VERSION_MICRO = 1;
|
||||
|
||||
constexpr u32 AtmosphereTargetFirmwareWithRevision(u8 major, u8 minor, u8 micro, u8 rev) {
|
||||
return u32{major} << 24 | u32{minor} << 16 | u32{micro} << 8 | u32{rev};
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -50,8 +53,8 @@ constexpr inline u32 RequiredKernelVersion =
|
|||
|
||||
// This is the highest SVC version supported, to be updated on new kernel releases.
|
||||
// NOTE: Official kernel versions have SVC major = SDK major + 4, SVC minor = SDK minor.
|
||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(15);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(3);
|
||||
constexpr inline u32 SupportedKernelMajorVersion = ConvertToSvcMajorVersion(20);
|
||||
constexpr inline u32 SupportedKernelMinorVersion = ConvertToSvcMinorVersion(5);
|
||||
constexpr inline u32 SupportedKernelVersion =
|
||||
EncodeKernelVersion(SupportedKernelMajorVersion, SupportedKernelMinorVersion);
|
||||
|
||||
|
|
|
@ -462,6 +462,9 @@ GMainWindow::GMainWindow(bool has_broken_vulkan)
|
|||
// Gen keys if necessary
|
||||
OnCheckFirmwareDecryption();
|
||||
|
||||
// Check firmware
|
||||
OnCheckFirmware();
|
||||
|
||||
game_list->LoadCompatibilityList();
|
||||
// force reload on first load to ensure add-ons get updated
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs, false);
|
||||
|
@ -4326,6 +4329,7 @@ void GMainWindow::OnInstallFirmware() {
|
|||
|
||||
progress.close();
|
||||
OnCheckFirmwareDecryption();
|
||||
OnCheckFirmware();
|
||||
}
|
||||
|
||||
void GMainWindow::OnInstallDecryptionKeys() {
|
||||
|
@ -4404,6 +4408,7 @@ void GMainWindow::OnInstallDecryptionKeys() {
|
|||
}
|
||||
|
||||
OnCheckFirmwareDecryption();
|
||||
OnCheckFirmware();
|
||||
}
|
||||
|
||||
void GMainWindow::OnAbout() {
|
||||
|
@ -5067,6 +5072,34 @@ void GMainWindow::OnCheckFirmwareDecryption() {
|
|||
UpdateMenuState();
|
||||
}
|
||||
|
||||
void GMainWindow::OnCheckFirmware()
|
||||
{
|
||||
if (!CheckFirmwarePresence()) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Firmware Missing"),
|
||||
tr("Firmware missing. Firmware is required to run certain games and use the Home Menu.\n"
|
||||
"Eden only works with firmware 19.0.1 and earlier."));
|
||||
} else {
|
||||
Service::Set::FirmwareVersionFormat firmware_data{};
|
||||
const auto result = Service::Set::GetFirmwareVersionImpl(
|
||||
firmware_data, *system, Service::Set::GetFirmwareVersionType::Version2);
|
||||
|
||||
if (result.IsError()) {
|
||||
LOG_INFO(Frontend, "Unable to read firmware");
|
||||
QMessageBox::warning(
|
||||
this, tr("Firmware Corrupted"),
|
||||
tr("Firmware reported as present, but was unable to be read. Check for decryption keys and redump firmware if necessary."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (firmware_data.major > 19) {
|
||||
QMessageBox::warning(
|
||||
this, tr("Firmware Too New"),
|
||||
tr("Firmware is too new. Eden only works with firmware 19.0.1 and earlier."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GMainWindow::CheckFirmwarePresence() {
|
||||
constexpr u64 MiiEditId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2014 Citra Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
|
@ -414,6 +417,7 @@ private slots:
|
|||
void OnCreateHomeMenuShortcut(GameListShortcutTarget target);
|
||||
void OnCaptureScreenshot();
|
||||
void OnCheckFirmwareDecryption();
|
||||
void OnCheckFirmware();
|
||||
void OnLanguageChanged(const QString& locale);
|
||||
void OnMouseActivity();
|
||||
bool OnShutdownBegin();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue