diff options
Diffstat (limited to 'src/android')
14 files changed, 235 insertions, 53 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index cc38141456..fb15783426 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -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 { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 3435d08132..c7d6d6c33a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt @@ -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 @@ -408,6 +409,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 * * @param path Path to game file. Can be a [Uri]. diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index f43e5f9dd6..4c527163c8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt @@ -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"), diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 84c9f419a4..b52355e255 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt @@ -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( diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 24214c3895..2337bc5821 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt @@ -271,6 +271,8 @@ class SettingsFragmentPresenter( if (Build.VERSION.SDK_INT >= 31) { add(BooleanSetting.SHOW_SOC_MODEL.key) } + + add(BooleanSetting.SHOW_FW_VERSION.key) } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt index 4b7da6ef23..641522de4d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt @@ -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())) { diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt index f9ecd6f49f..f39d9514b3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt @@ -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 ) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt index ee3bb0386a..26fcf7c0db 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ProgressDialogFragment.kt @@ -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" diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt index 6828b32e84..6443067885 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt @@ -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 { @@ -168,6 +168,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, R.string.games, R.string.games_description, @@ -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 = diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt index 08eee8c815..97a60ee184 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt @@ -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 + } } diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt index 3e3759d7eb..3a9c5486a8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt @@ -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") } + processFirmware(result) + } - val firmwarePath = - File(DirectoryInitialization.userDirectory + "/nand/system/Contents/registered/") - val cacheFirmwareDir = File("${cacheDir.path}/registered/") + fun processFirmware(result: Uri, onComplete: (() -> Unit)? = null) { + val filterNCA = FilenameFilter { _, dirName -> dirName.endsWith(".nca") } - ProgressDialogFragment.newInstance( - this, - R.string.firmware_installing - ) { progressCallback, _ -> - var messageToShow: Any - try { - FileUtil.unzipToInternalStorage( - result.toString(), - cacheFirmwareDir, - progressCallback + 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 ) - 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() + } else { + firmwarePath.deleteRecursively() + cacheFirmwareDir.copyRecursively(firmwarePath, true) + NativeLibrary.initializeSystem(true) + homeViewModel.setCheckKeys(true) + homeViewModel.setCheckFirmware(true) + getString(R.string.save_file_imported_success) } - messageToShow - }.show(supportFragmentManager, ProgressDialogFragment.TAG) - } + } 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) diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 14d16a2182..67d70a6adc 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -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, diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index cc00cfe024..4dd6f833b0 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp @@ -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) { diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 10d02b4b82..d09da35546 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -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> |
