diff --git a/CMakeLists.txt b/CMakeLists.txt index 0540415eb..9cde23779 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,8 +164,7 @@ endif() if (CITRON_USE_BUNDLED_VCPKG) if (ANDROID) - set(ENV{ANDROID_NDK_HOME} ${ANDROID_NDK}) - set(VCPKG_ADDITIONAL_FLAGS "--allow-unsupported") + set(ENV{ANDROID_NDK_HOME} "${ANDROID_NDK}") list(APPEND VCPKG_MANIFEST_FEATURES "android") if (CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a") diff --git a/src/android/app/src/main/java/org/citron/citron_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/citron/citron_emu/activities/EmulationActivity.kt index dee584378..c4c2c1ed1 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/activities/EmulationActivity.kt @@ -83,6 +83,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { super.onCreate(savedInstanceState) + // Check if firmware is available + if (!NativeLibrary.isFirmwareAvailable()) { + AlertDialog.Builder(this) + .setTitle(R.string.firmware_missing_title) + .setMessage(R.string.firmware_missing_message) + .setPositiveButton(R.string.ok) { _, _ -> + finish() + } + .setCancelable(false) + .show() + return + } + // Add license verification at the start LicenseVerifier.verifyLicense(this) @@ -155,13 +168,22 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean { if (event.action == KeyEvent.ACTION_DOWN) { - val textChar = event.unicodeChar - if (textChar == 0) { - // No text, button input. - NativeLibrary.submitInlineKeyboardInput(keyCode) + if (keyCode == KeyEvent.KEYCODE_ENTER) { + // Special case, we do not support multiline input, dismiss the keyboard. + val overlayView: View = + this.findViewById(R.id.surface_input_overlay) + val im = + overlayView.context.getSystemService(INPUT_METHOD_SERVICE) as InputMethodManager + im.hideSoftInputFromWindow(overlayView.windowToken, 0) } else { - // Text submitted. - NativeLibrary.submitInlineKeyboardText(textChar.toChar().toString()) + val textChar = event.unicodeChar + if (textChar == 0) { + // No text, button input. + NativeLibrary.submitInlineKeyboardInput(keyCode) + } else { + // Text submitted. + NativeLibrary.submitInlineKeyboardText(textChar.toChar().toString()) + } } } return super.onKeyDown(keyCode, event) diff --git a/src/android/app/src/main/java/org/citron/citron_emu/fragments/SetupFragment.kt b/src/android/app/src/main/java/org/citron/citron_emu/fragments/SetupFragment.kt index d7c759507..962fa709a 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/fragments/SetupFragment.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/fragments/SetupFragment.kt @@ -181,6 +181,61 @@ class SetupFragment : Fragment() { ) ) + // Add title.keys installation page + add( + SetupPage( + R.drawable.ic_key, + R.string.install_title_keys, + R.string.install_title_keys_description, + R.drawable.ic_add, + true, + R.string.select_keys, + { + titleKeyCallback = it + getTitleKey.launch(arrayOf("*/*")) + }, + true, + R.string.install_title_keys_warning, + R.string.install_title_keys_warning_description, + R.string.install_title_keys_warning_help, + { + val file = File(DirectoryInitialization.userDirectory + "/keys/title.keys") + if (file.exists()) { + StepState.COMPLETE + } else { + StepState.INCOMPLETE + } + } + ) + ) + + // Add firmware installation page (mandatory) + add( + SetupPage( + R.drawable.ic_key, + R.string.install_firmware, + R.string.install_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, @@ -269,6 +324,18 @@ class SetupFragment : Fragment() { return@setOnClickListener } + // Special handling for firmware page - don't allow skipping + if (currentPage.titleId == R.string.install_firmware && !NativeLibrary.isFirmwareAvailable()) { + SetupWarningDialogFragment.newInstance( + currentPage.warningTitleId, + currentPage.warningDescriptionId, + currentPage.warningHelpLinkId, + index, + allowSkip = false + ).show(childFragmentManager, SetupWarningDialogFragment.TAG) + return@setOnClickListener + } + if (!hasBeenWarned[index]) { SetupWarningDialogFragment.newInstance( currentPage.warningTitleId, @@ -347,6 +414,30 @@ class SetupFragment : Fragment() { } } + private lateinit var titleKeyCallback: SetupCallback + + val getTitleKey = + registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> + if (result != null) { + mainActivity.processTitleKey(result) + titleKeyCallback.onStepCompleted() + } + } + + private lateinit var firmwareCallback: SetupCallback + + val getFirmware = + registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> + if (result != null) { + mainActivity.getFirmware.launch(arrayOf("application/zip")) + binding.root.postDelayed({ + if (NativeLibrary.isFirmwareAvailable()) { + firmwareCallback.onStepCompleted() + } + }, 1000) + } + } + private lateinit var gamesDirCallback: SetupCallback val getGamesDirectory = diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index e2956b73a..0135d6f81 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -260,10 +260,12 @@ std::unique_ptr GetLoader(Core::System& system, FileSys::VirtualFile if (bis_system) { auto mii_applet_nca = bis_system->GetEntry(MiiEditId, FileSys::ContentRecordType::Program); if (!mii_applet_nca) { - LOG_WARNING(Loader, "Firmware is not available. Some games may not function correctly."); + LOG_ERROR(Loader, "Firmware is required to launch games but is not available"); + return nullptr; } } else { - LOG_WARNING(Loader, "System NAND contents not available"); + LOG_ERROR(Loader, "System NAND contents not available"); + return nullptr; } FileType type = IdentifyFile(file); diff --git a/vcpkg.json b/vcpkg.json index 3c57e651d..b6dd63612 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,7 +1,7 @@ { "$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json", "name": "citron", - "builtin-baseline": "c82f74667287d3dc386bce81e44964370c91a289", + "builtin-baseline": "bc994510d2eb11aac7b43b03f67a7751d5bfe0e4", "version": "1.0", "dependencies": [ "boost-algorithm",