summaryrefslogtreecommitdiff
path: root/src/android/app
diff options
context:
space:
mode:
authorGravatar liamwhite2024-01-25 16:21:29 -0500
committerGravatar GitHub2024-01-25 16:21:29 -0500
commit3e2d3548f2bf90f823fb9c565ca2b97be3d048b7 (patch)
tree74137247efc83f233a4d81260de41eeb8aae1d8d /src/android/app
parentMerge pull request #12783 from liamwhite/cmif-generation (diff)
parentandroid: Add key check (diff)
downloadyuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.gz
yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.xz
yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.zip
Merge pull request #12777 from t895/firmware-warning
android: Add key warning
Diffstat (limited to 'src/android/app')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt32
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/HomeViewModel.kt7
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt42
-rw-r--r--src/android/app/src/main/jni/native.cpp21
-rw-r--r--src/android/app/src/main/res/values/strings.xml3
7 files changed, 99 insertions, 17 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 5b9f553f7..55abba093 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
@@ -620,6 +620,11 @@ object NativeLibrary {
620 external fun clearFilesystemProvider() 620 external fun clearFilesystemProvider()
621 621
622 /** 622 /**
623 * Checks if all necessary keys are present for decryption
624 */
625 external fun areKeysPresent(): Boolean
626
627 /**
623 * Button type for use in onTouchEvent 628 * Button type for use in onTouchEvent
624 */ 629 */
625 object ButtonType { 630 object ButtonType {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt
index 620d8db7c..22b084b9a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt
@@ -26,9 +26,15 @@ class MessageDialogFragment : DialogFragment() {
26 val descriptionId = requireArguments().getInt(DESCRIPTION_ID) 26 val descriptionId = requireArguments().getInt(DESCRIPTION_ID)
27 val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!! 27 val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!!
28 val helpLinkId = requireArguments().getInt(HELP_LINK) 28 val helpLinkId = requireArguments().getInt(HELP_LINK)
29 val dismissible = requireArguments().getBoolean(DISMISSIBLE)
30 val clearPositiveAction = requireArguments().getBoolean(CLEAR_POSITIVE_ACTION)
29 31
30 val builder = MaterialAlertDialogBuilder(requireContext()) 32 val builder = MaterialAlertDialogBuilder(requireContext())
31 33
34 if (clearPositiveAction) {
35 messageDialogViewModel.positiveAction = null
36 }
37
32 if (messageDialogViewModel.positiveAction == null) { 38 if (messageDialogViewModel.positiveAction == null) {
33 builder.setPositiveButton(R.string.close, null) 39 builder.setPositiveButton(R.string.close, null)
34 } else { 40 } else {
@@ -51,6 +57,8 @@ class MessageDialogFragment : DialogFragment() {
51 } 57 }
52 } 58 }
53 59
60 isCancelable = dismissible
61
54 return builder.show() 62 return builder.show()
55 } 63 }
56 64
@@ -67,6 +75,8 @@ class MessageDialogFragment : DialogFragment() {
67 private const val DESCRIPTION_ID = "DescriptionId" 75 private const val DESCRIPTION_ID = "DescriptionId"
68 private const val DESCRIPTION_STRING = "DescriptionString" 76 private const val DESCRIPTION_STRING = "DescriptionString"
69 private const val HELP_LINK = "Link" 77 private const val HELP_LINK = "Link"
78 private const val DISMISSIBLE = "Dismissible"
79 private const val CLEAR_POSITIVE_ACTION = "ClearPositiveAction"
70 80
71 fun newInstance( 81 fun newInstance(
72 activity: FragmentActivity? = null, 82 activity: FragmentActivity? = null,
@@ -75,22 +85,28 @@ class MessageDialogFragment : DialogFragment() {
75 descriptionId: Int = 0, 85 descriptionId: Int = 0,
76 descriptionString: String = "", 86 descriptionString: String = "",
77 helpLinkId: Int = 0, 87 helpLinkId: Int = 0,
88 dismissible: Boolean = true,
78 positiveAction: (() -> Unit)? = null 89 positiveAction: (() -> Unit)? = null
79 ): MessageDialogFragment { 90 ): MessageDialogFragment {
91 var clearPositiveAction = false
92 if (activity != null) {
93 ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
94 clear()
95 this.positiveAction = positiveAction
96 }
97 } else {
98 clearPositiveAction = true
99 }
100
80 val dialog = MessageDialogFragment() 101 val dialog = MessageDialogFragment()
81 val bundle = Bundle() 102 val bundle = Bundle().apply {
82 bundle.apply {
83 putInt(TITLE_ID, titleId) 103 putInt(TITLE_ID, titleId)
84 putString(TITLE_STRING, titleString) 104 putString(TITLE_STRING, titleString)
85 putInt(DESCRIPTION_ID, descriptionId) 105 putInt(DESCRIPTION_ID, descriptionId)
86 putString(DESCRIPTION_STRING, descriptionString) 106 putString(DESCRIPTION_STRING, descriptionString)
87 putInt(HELP_LINK, helpLinkId) 107 putInt(HELP_LINK, helpLinkId)
88 } 108 putBoolean(DISMISSIBLE, dismissible)
89 if (activity != null) { 109 putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction)
90 ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply {
91 clear()
92 this.positiveAction = positiveAction
93 }
94 } 110 }
95 dialog.arguments = bundle 111 dialog.arguments = bundle
96 return dialog 112 return dialog
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 064342cdd..ebf41a639 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
@@ -31,6 +31,7 @@ import androidx.preference.PreferenceManager
31import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback 31import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
32import com.google.android.material.transition.MaterialFadeThrough 32import com.google.android.material.transition.MaterialFadeThrough
33import kotlinx.coroutines.launch 33import kotlinx.coroutines.launch
34import org.yuzu.yuzu_emu.NativeLibrary
34import java.io.File 35import java.io.File
35import org.yuzu.yuzu_emu.R 36import org.yuzu.yuzu_emu.R
36import org.yuzu.yuzu_emu.YuzuApplication 37import org.yuzu.yuzu_emu.YuzuApplication
@@ -162,7 +163,7 @@ class SetupFragment : Fragment() {
162 R.string.install_prod_keys_warning_help, 163 R.string.install_prod_keys_warning_help,
163 { 164 {
164 val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys") 165 val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys")
165 if (file.exists()) { 166 if (file.exists() && NativeLibrary.areKeysPresent()) {
166 StepState.COMPLETE 167 StepState.COMPLETE
167 } else { 168 } else {
168 StepState.INCOMPLETE 169 StepState.INCOMPLETE
@@ -347,7 +348,8 @@ class SetupFragment : Fragment() {
347 val getProdKey = 348 val getProdKey =
348 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 349 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
349 if (result != null) { 350 if (result != null) {
350 if (mainActivity.processKey(result)) { 351 mainActivity.processKey(result)
352 if (NativeLibrary.areKeysPresent()) {
351 keyCallback.onStepCompleted() 353 keyCallback.onStepCompleted()
352 } 354 }
353 } 355 }
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 513ac2fc5..cfc777b81 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
@@ -31,6 +31,9 @@ class HomeViewModel : ViewModel() {
31 private val _reloadPropertiesList = MutableStateFlow(false) 31 private val _reloadPropertiesList = MutableStateFlow(false)
32 val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow() 32 val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow()
33 33
34 private val _checkKeys = MutableStateFlow(false)
35 val checkKeys = _checkKeys.asStateFlow()
36
34 var navigatedToSetup = false 37 var navigatedToSetup = false
35 38
36 fun setNavigationVisibility(visible: Boolean, animated: Boolean) { 39 fun setNavigationVisibility(visible: Boolean, animated: Boolean) {
@@ -66,4 +69,8 @@ class HomeViewModel : ViewModel() {
66 fun reloadPropertiesList(reload: Boolean) { 69 fun reloadPropertiesList(reload: Boolean) {
67 _reloadPropertiesList.value = reload 70 _reloadPropertiesList.value = reload
68 } 71 }
72
73 fun setCheckKeys(value: Boolean) {
74 _checkKeys.value = value
75 }
69} 76}
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 c2cc29961..b3967d294 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
@@ -64,6 +64,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
64 64
65 override var themeId: Int = 0 65 override var themeId: Int = 0
66 66
67 private val CHECKED_DECRYPTION = "CheckedDecryption"
68 private var checkedDecryption = false
69
67 override fun onCreate(savedInstanceState: Bundle?) { 70 override fun onCreate(savedInstanceState: Bundle?) {
68 val splashScreen = installSplashScreen() 71 val splashScreen = installSplashScreen()
69 splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } 72 splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady }
@@ -75,6 +78,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
75 binding = ActivityMainBinding.inflate(layoutInflater) 78 binding = ActivityMainBinding.inflate(layoutInflater)
76 setContentView(binding.root) 79 setContentView(binding.root)
77 80
81 if (savedInstanceState != null) {
82 checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION)
83 }
84 if (!checkedDecryption) {
85 val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
86 .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
87 if (!firstTimeSetup) {
88 checkKeys()
89 }
90 checkedDecryption = true
91 }
92
78 WindowCompat.setDecorFitsSystemWindows(window, false) 93 WindowCompat.setDecorFitsSystemWindows(window, false)
79 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) 94 window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
80 95
@@ -150,6 +165,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
150 } 165 }
151 } 166 }
152 } 167 }
168 launch {
169 repeatOnLifecycle(Lifecycle.State.CREATED) {
170 homeViewModel.checkKeys.collect {
171 if (it) {
172 checkKeys()
173 homeViewModel.setCheckKeys(false)
174 }
175 }
176 }
177 }
153 } 178 }
154 179
155 // Dismiss previous notifications (should not happen unless a crash occurred) 180 // Dismiss previous notifications (should not happen unless a crash occurred)
@@ -158,6 +183,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
158 setInsets() 183 setInsets()
159 } 184 }
160 185
186 private fun checkKeys() {
187 if (!NativeLibrary.areKeysPresent()) {
188 MessageDialogFragment.newInstance(
189 titleId = R.string.keys_missing,
190 descriptionId = R.string.keys_missing_description,
191 helpLinkId = R.string.keys_missing_help
192 ).show(supportFragmentManager, MessageDialogFragment.TAG)
193 }
194 }
195
196 override fun onSaveInstanceState(outState: Bundle) {
197 super.onSaveInstanceState(outState)
198 outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption)
199 }
200
161 fun finishSetup(navController: NavController) { 201 fun finishSetup(navController: NavController) {
162 navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment) 202 navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment)
163 (binding.navigationView as NavigationBarView).setupWithNavController(navController) 203 (binding.navigationView as NavigationBarView).setupWithNavController(navController)
@@ -349,6 +389,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
349 R.string.install_keys_success, 389 R.string.install_keys_success,
350 Toast.LENGTH_SHORT 390 Toast.LENGTH_SHORT
351 ).show() 391 ).show()
392 homeViewModel.setCheckKeys(true)
352 gamesViewModel.reloadGames(true) 393 gamesViewModel.reloadGames(true)
353 return true 394 return true
354 } else { 395 } else {
@@ -399,6 +440,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
399 firmwarePath.deleteRecursively() 440 firmwarePath.deleteRecursively()
400 cacheFirmwareDir.copyRecursively(firmwarePath, true) 441 cacheFirmwareDir.copyRecursively(firmwarePath, true)
401 NativeLibrary.initializeSystem(true) 442 NativeLibrary.initializeSystem(true)
443 homeViewModel.setCheckKeys(true)
402 getString(R.string.save_file_imported_success) 444 getString(R.string.save_file_imported_success)
403 } 445 }
404 } catch (e: Exception) { 446 } catch (e: Exception) {
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index c20c2d2b8..247f2c2b3 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -464,8 +464,8 @@ int Java_org_yuzu_yuzu_1emu_NativeLibrary_installFileToNand(JNIEnv* env, jobject
464 }; 464 };
465 465
466 return static_cast<int>( 466 return static_cast<int>(
467 ContentManager::InstallNSP(&EmulationSession::GetInstance().System(), 467 ContentManager::InstallNSP(EmulationSession::GetInstance().System(),
468 EmulationSession::GetInstance().System().GetFilesystem().get(), 468 *EmulationSession::GetInstance().System().GetFilesystem(),
469 GetJString(env, j_file), callback)); 469 GetJString(env, j_file), callback));
470} 470}
471 471
@@ -825,7 +825,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject job
825void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj, 825void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj,
826 jstring jprogramId) { 826 jstring jprogramId) {
827 auto program_id = EmulationSession::GetProgramId(env, jprogramId); 827 auto program_id = EmulationSession::GetProgramId(env, jprogramId);
828 ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id); 828 ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id);
829} 829}
830 830
831void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId, 831void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj, jstring jprogramId,
@@ -835,8 +835,9 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeMod(JNIEnv* env, jobject jobj,
835 program_id, GetJString(env, jname)); 835 program_id, GetJString(env, jname));
836} 836}
837 837
838jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobject jobj, 838jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env,
839 jobject jcallback) { 839 jobject jobj,
840 jobject jcallback) {
840 auto jlambdaClass = env->GetObjectClass(jcallback); 841 auto jlambdaClass = env->GetObjectClass(jcallback);
841 auto jlambdaInvokeMethod = env->GetMethodID( 842 auto jlambdaInvokeMethod = env->GetMethodID(
842 jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 843 jlambdaClass, "invoke", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
@@ -848,7 +849,7 @@ jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* en
848 849
849 auto& session = EmulationSession::GetInstance(); 850 auto& session = EmulationSession::GetInstance();
850 std::vector<std::string> result = ContentManager::VerifyInstalledContents( 851 std::vector<std::string> result = ContentManager::VerifyInstalledContents(
851 &session.System(), session.GetContentProvider(), callback); 852 session.System(), *session.GetContentProvider(), callback);
852 jobjectArray jresult = 853 jobjectArray jresult =
853 env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, "")); 854 env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, ""));
854 for (size_t i = 0; i < result.size(); ++i) { 855 for (size_t i = 0; i < result.size(); ++i) {
@@ -869,7 +870,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje
869 }; 870 };
870 auto& session = EmulationSession::GetInstance(); 871 auto& session = EmulationSession::GetInstance();
871 return static_cast<jint>( 872 return static_cast<jint>(
872 ContentManager::VerifyGameContents(&session.System(), GetJString(env, jpath), callback)); 873 ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback));
873} 874}
874 875
875jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj, 876jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getSavePath(JNIEnv* env, jobject jobj,
@@ -918,4 +919,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env,
918 EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); 919 EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries();
919} 920}
920 921
922jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) {
923 auto& system = EmulationSession::GetInstance().System();
924 system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
925 return ContentManager::AreKeysPresent();
926}
927
921} // extern "C" 928} // extern "C"
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index 779eb36a8..3cd1586fd 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -144,6 +144,9 @@
144 <string name="no_save_data_found">No save data found</string> 144 <string name="no_save_data_found">No save data found</string>
145 <string name="verify_installed_content">Verify installed content</string> 145 <string name="verify_installed_content">Verify installed content</string>
146 <string name="verify_installed_content_description">Checks all installed content for corruption</string> 146 <string name="verify_installed_content_description">Checks all installed content for corruption</string>
147 <string name="keys_missing">Encryption keys are missing</string>
148 <string name="keys_missing_description">Firmware and retail games cannot be decrypted</string>
149 <string name="keys_missing_help">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
147 150
148 <!-- Applet launcher strings --> 151 <!-- Applet launcher strings -->
149 <string name="applets">Applet launcher</string> 152 <string name="applets">Applet launcher</string>