summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt13
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt58
-rw-r--r--src/android/app/src/main/jni/native.cpp86
-rw-r--r--src/android/app/src/main/res/drawable/ic_system_update_alt.xml9
-rw-r--r--src/android/app/src/main/res/values/strings.xml9
-rw-r--r--src/core/file_sys/submission_package.h1
7 files changed, 183 insertions, 5 deletions
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 22af9e435..4be9ade14 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
@@ -227,6 +227,8 @@ object NativeLibrary {
227 227
228 external fun setAppDirectory(directory: String) 228 external fun setAppDirectory(directory: String)
229 229
230 external fun installFileToNand(filename: String): Int
231
230 external fun initializeGpuDriver( 232 external fun initializeGpuDriver(
231 hookLibDir: String?, 233 hookLibDir: String?,
232 customDriverDir: String?, 234 customDriverDir: String?,
@@ -507,4 +509,15 @@ object NativeLibrary {
507 const val RELEASED = 0 509 const val RELEASED = 0
508 const val PRESSED = 1 510 const val PRESSED = 1
509 } 511 }
512
513 /**
514 * Result from installFileToNand
515 */
516 object InstallFileToNandResult {
517 const val Success = 0
518 const val SuccessFileOverwritten = 1
519 const val Error = 2
520 const val ErrorBaseGame = 3
521 const val ErrorFilenameExtension = 4
522 }
510} 523}
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 bdc337501..536163eb6 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
@@ -95,6 +95,11 @@ class HomeSettingsFragment : Fragment() {
95 R.drawable.ic_nfc 95 R.drawable.ic_nfc
96 ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) }, 96 ) { mainActivity.getAmiiboKey.launch(arrayOf("*/*")) },
97 HomeSetting( 97 HomeSetting(
98 R.string.install_game_content,
99 R.string.install_game_content_description,
100 R.drawable.ic_system_update_alt
101 ) { mainActivity.installGameUpdate.launch(arrayOf("*/*")) },
102 HomeSetting(
98 R.string.select_games_folder, 103 R.string.select_games_folder,
99 R.string.select_games_folder_description, 104 R.string.select_games_folder_description,
100 R.drawable.ic_add 105 R.drawable.ic_add
@@ -103,7 +108,12 @@ class HomeSettingsFragment : Fragment() {
103 R.string.manage_save_data, 108 R.string.manage_save_data,
104 R.string.import_export_saves_description, 109 R.string.import_export_saves_description,
105 R.drawable.ic_save 110 R.drawable.ic_save
106 ) { ImportExportSavesFragment().show(parentFragmentManager, ImportExportSavesFragment.TAG) }, 111 ) {
112 ImportExportSavesFragment().show(
113 parentFragmentManager,
114 ImportExportSavesFragment.TAG
115 )
116 },
107 HomeSetting( 117 HomeSetting(
108 R.string.install_prod_keys, 118 R.string.install_prod_keys,
109 R.string.install_prod_keys_description, 119 R.string.install_prod_keys_description,
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 3fca0a7e6..041d16f3a 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
@@ -467,4 +467,62 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
467 } 467 }
468 } 468 }
469 } 469 }
470
471 val installGameUpdate =
472 registerForActivityResult(ActivityResultContracts.OpenDocument()) {
473 if (it == null)
474 return@registerForActivityResult
475
476 IndeterminateProgressDialogFragment.newInstance(
477 this@MainActivity,
478 R.string.install_game_content
479 ) {
480 val result = NativeLibrary.installFileToNand(it.toString())
481 lifecycleScope.launch {
482 withContext(Dispatchers.Main) {
483 when (result) {
484 NativeLibrary.InstallFileToNandResult.Success -> {
485 Toast.makeText(
486 applicationContext,
487 R.string.install_game_content_success,
488 Toast.LENGTH_SHORT
489 ).show()
490 }
491
492 NativeLibrary.InstallFileToNandResult.SuccessFileOverwritten -> {
493 Toast.makeText(
494 applicationContext,
495 R.string.install_game_content_success_overwrite,
496 Toast.LENGTH_SHORT
497 ).show()
498 }
499
500 NativeLibrary.InstallFileToNandResult.ErrorBaseGame -> {
501 MessageDialogFragment.newInstance(
502 R.string.install_game_content_failure,
503 R.string.install_game_content_failure_base
504 ).show(supportFragmentManager, MessageDialogFragment.TAG)
505 }
506
507 NativeLibrary.InstallFileToNandResult.ErrorFilenameExtension -> {
508 MessageDialogFragment.newInstance(
509 R.string.install_game_content_failure,
510 R.string.install_game_content_failure_file_extension,
511 R.string.install_game_content_help_link
512 ).show(supportFragmentManager, MessageDialogFragment.TAG)
513 }
514
515 else -> {
516 MessageDialogFragment.newInstance(
517 R.string.install_game_content_failure,
518 R.string.install_game_content_failure_description,
519 R.string.install_game_content_help_link
520 ).show(supportFragmentManager, MessageDialogFragment.TAG)
521 }
522 }
523 }
524 }
525 return@newInstance result
526 }.show(supportFragmentManager, IndeterminateProgressDialogFragment.TAG)
527 }
470} 528}
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 7ebed5e6a..4091c23d1 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -28,7 +28,10 @@
28#include "core/core.h" 28#include "core/core.h"
29#include "core/cpu_manager.h" 29#include "core/cpu_manager.h"
30#include "core/crypto/key_manager.h" 30#include "core/crypto/key_manager.h"
31#include "core/file_sys/card_image.h"
31#include "core/file_sys/registered_cache.h" 32#include "core/file_sys/registered_cache.h"
33#include "core/file_sys/submission_package.h"
34#include "core/file_sys/vfs.h"
32#include "core/file_sys/vfs_real.h" 35#include "core/file_sys/vfs_real.h"
33#include "core/frontend/applets/cabinet.h" 36#include "core/frontend/applets/cabinet.h"
34#include "core/frontend/applets/controller.h" 37#include "core/frontend/applets/controller.h"
@@ -94,6 +97,74 @@ public:
94 m_native_window = native_window; 97 m_native_window = native_window;
95 } 98 }
96 99
100 int InstallFileToNand(std::string filename) {
101 const auto copy_func = [](const FileSys::VirtualFile& src, const FileSys::VirtualFile& dest,
102 std::size_t block_size) {
103 if (src == nullptr || dest == nullptr) {
104 return false;
105 }
106 if (!dest->Resize(src->GetSize())) {
107 return false;
108 }
109
110 using namespace Common::Literals;
111 std::vector<u8> buffer(1_MiB);
112
113 for (std::size_t i = 0; i < src->GetSize(); i += buffer.size()) {
114 const auto read = src->Read(buffer.data(), buffer.size(), i);
115 dest->Write(buffer.data(), read, i);
116 }
117 return true;
118 };
119
120 enum InstallResult {
121 Success = 0,
122 SuccessFileOverwritten = 1,
123 InstallError = 2,
124 ErrorBaseGame = 3,
125 ErrorFilenameExtension = 4,
126 };
127
128 m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
129 m_system.GetFileSystemController().CreateFactories(*m_vfs);
130
131 std::shared_ptr<FileSys::NSP> nsp;
132 if (filename.ends_with("nsp")) {
133 nsp = std::make_shared<FileSys::NSP>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
134 if (nsp->IsExtractedType()) {
135 return InstallError;
136 }
137 } else if (filename.ends_with("xci")) {
138 const auto xci =
139 std::make_shared<FileSys::XCI>(m_vfs->OpenFile(filename, FileSys::Mode::Read));
140 nsp = xci->GetSecurePartitionNSP();
141 } else {
142 return ErrorFilenameExtension;
143 }
144
145 if (!nsp) {
146 return InstallError;
147 }
148
149 if (nsp->GetStatus() != Loader::ResultStatus::Success) {
150 return InstallError;
151 }
152
153 const auto res = m_system.GetFileSystemController().GetUserNANDContents()->InstallEntry(
154 *nsp, true, copy_func);
155
156 switch (res) {
157 case FileSys::InstallResult::Success:
158 return Success;
159 case FileSys::InstallResult::OverwriteExisting:
160 return SuccessFileOverwritten;
161 case FileSys::InstallResult::ErrorBaseInstall:
162 return ErrorBaseGame;
163 default:
164 return InstallError;
165 }
166 }
167
97 void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir, 168 void InitializeGpuDriver(const std::string& hook_lib_dir, const std::string& custom_driver_dir,
98 const std::string& custom_driver_name, 169 const std::string& custom_driver_name,
99 const std::string& file_redirect_dir) { 170 const std::string& file_redirect_dir) {
@@ -154,14 +225,14 @@ public:
154 m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window, 225 m_window = std::make_unique<EmuWindow_Android>(&m_input_subsystem, m_native_window,
155 m_vulkan_library); 226 m_vulkan_library);
156 227
228 m_system.SetFilesystem(m_vfs);
229
157 // Initialize system. 230 // Initialize system.
158 auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>(); 231 auto android_keyboard = std::make_unique<SoftwareKeyboard::AndroidKeyboard>();
159 m_software_keyboard = android_keyboard.get(); 232 m_software_keyboard = android_keyboard.get();
160 m_system.SetShuttingDown(false); 233 m_system.SetShuttingDown(false);
161 m_system.ApplySettings(); 234 m_system.ApplySettings();
162 m_system.HIDCore().ReloadInputDevices(); 235 m_system.HIDCore().ReloadInputDevices();
163 m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
164 m_system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
165 m_system.SetAppletFrontendSet({ 236 m_system.SetAppletFrontendSet({
166 nullptr, // Amiibo Settings 237 nullptr, // Amiibo Settings
167 nullptr, // Controller Selector 238 nullptr, // Controller Selector
@@ -173,7 +244,8 @@ public:
173 std::move(android_keyboard), // Software Keyboard 244 std::move(android_keyboard), // Software Keyboard
174 nullptr, // Web Browser 245 nullptr, // Web Browser
175 }); 246 });
176 m_system.GetFileSystemController().CreateFactories(*m_system.GetFilesystem()); 247 m_system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
248 m_system.GetFileSystemController().CreateFactories(*m_vfs);
177 249
178 // Initialize account manager 250 // Initialize account manager
179 m_profile_manager = std::make_unique<Service::Account::ProfileManager>(); 251 m_profile_manager = std::make_unique<Service::Account::ProfileManager>();
@@ -398,7 +470,7 @@ private:
398 InputCommon::InputSubsystem m_input_subsystem; 470 InputCommon::InputSubsystem m_input_subsystem;
399 Common::DetachedTasks m_detached_tasks; 471 Common::DetachedTasks m_detached_tasks;
400 Core::PerfStatsResults m_perf_stats{}; 472 Core::PerfStatsResults m_perf_stats{};
401 std::shared_ptr<FileSys::RealVfsFilesystem> m_vfs; 473 std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
402 Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized}; 474 Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
403 bool m_is_running{}; 475 bool m_is_running{};
404 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{}; 476 SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
@@ -466,6 +538,12 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
466 Common::FS::SetAppDirectory(GetJString(env, j_directory)); 538 Common::FS::SetAppDirectory(GetJString(env, j_directory));
467} 539}
468 540
541int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env,
542 [[maybe_unused]] jclass clazz,
543 jstring j_file) {
544 return EmulationSession::GetInstance().InstallFileToNand(GetJString(env, j_file));
545}
546
469void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver( 547void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
470 JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir, 548 JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
471 jstring custom_driver_name, jstring file_redirect_dir) { 549 jstring custom_driver_name, jstring file_redirect_dir) {
diff --git a/src/android/app/src/main/res/drawable/ic_system_update_alt.xml b/src/android/app/src/main/res/drawable/ic_system_update_alt.xml
new file mode 100644
index 000000000..0f6adfdb8
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_system_update_alt.xml
@@ -0,0 +1,9 @@
1<vector xmlns:android="http://schemas.android.com/apk/res/android"
2 android:width="48dp"
3 android:height="48dp"
4 android:viewportWidth="960"
5 android:viewportHeight="960">
6 <path
7 android:fillColor="#FF000000"
8 android:pathData="M140,800q-24,0 -42,-18t-18,-42v-520q0,-24 18,-42t42,-18h250v60L140,220v520h680v-520L570,220v-60h250q24,0 42,18t18,42v520q0,24 -18,42t-42,18L140,800ZM480,615L280,415l43,-43 127,127v-339h60v339l127,-127 43,43 -200,200Z"/>
9</vector>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 6e9d47557..7dae63dcb 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -102,6 +102,15 @@
102 <string name="share_log">Share debug logs</string> 102 <string name="share_log">Share debug logs</string>
103 <string name="share_log_description">Share yuzu\'s log file to debug issues</string> 103 <string name="share_log_description">Share yuzu\'s log file to debug issues</string>
104 <string name="share_log_missing">No log file found</string> 104 <string name="share_log_missing">No log file found</string>
105 <string name="install_game_content">Install game content</string>
106 <string name="install_game_content_description">Install game updates or DLC</string>
107 <string name="install_game_content_failure">Error installing file to NAND</string>
108 <string name="install_game_content_failure_description">Game content installation failed. Please ensure content is valid and that the prod.keys file is installed.</string>
109 <string name="install_game_content_failure_base">Installation of base games isn\'t permitted in order to avoid possible conflicts. Please select an update or DLC instead.</string>
110 <string name="install_game_content_failure_file_extension">The selected file type is not supported. Only NSP and XCI content is supported for this action. Please verify the game content is valid.</string>
111 <string name="install_game_content_success">Game content installed successfully</string>
112 <string name="install_game_content_success_overwrite">Game content was overwritten successfully</string>
113 <string name="install_game_content_help_link">https://yuzu-emu.org/help/quickstart/#dumping-installed-updates</string>
105 114
106 <!-- About screen strings --> 115 <!-- About screen strings -->
107 <string name="gaia_is_not_real">Gaia isn\'t real</string> 116 <string name="gaia_is_not_real">Gaia isn\'t real</string>
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index 3226b884a..27f97c725 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -8,6 +8,7 @@
8#include <set> 8#include <set>
9#include <vector> 9#include <vector>
10#include "common/common_types.h" 10#include "common/common_types.h"
11#include "core/file_sys/nca_metadata.h"
11#include "core/file_sys/vfs.h" 12#include "core/file_sys/vfs.h"
12 13
13namespace Core::Crypto { 14namespace Core::Crypto {