diff options
author | liamwhite <liamwhite@users.noreply.github.com> | 2024-01-25 22:21:29 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-01-25 22:21:29 +0100 |
commit | 3e2d3548f2bf90f823fb9c565ca2b97be3d048b7 (patch) | |
tree | 74137247efc83f233a4d81260de41eeb8aae1d8d /src/android/app | |
parent | Merge pull request #12783 from liamwhite/cmif-generation (diff) | |
parent | android: Add key check (diff) | |
download | yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.gz yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.bz2 yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.lz yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.xz yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.tar.zst yuzu-3e2d3548f2bf90f823fb9c565ca2b97be3d048b7.zip |
Diffstat (limited to 'src/android/app')
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 { external fun clearFilesystemProvider() /** + * Checks if all necessary keys are present for decryption + */ + external fun areKeysPresent(): Boolean + + /** * Button type for use in onTouchEvent */ 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() { val descriptionId = requireArguments().getInt(DESCRIPTION_ID) val descriptionString = requireArguments().getString(DESCRIPTION_STRING)!! val helpLinkId = requireArguments().getInt(HELP_LINK) + val dismissible = requireArguments().getBoolean(DISMISSIBLE) + val clearPositiveAction = requireArguments().getBoolean(CLEAR_POSITIVE_ACTION) val builder = MaterialAlertDialogBuilder(requireContext()) + if (clearPositiveAction) { + messageDialogViewModel.positiveAction = null + } + if (messageDialogViewModel.positiveAction == null) { builder.setPositiveButton(R.string.close, null) } else { @@ -51,6 +57,8 @@ class MessageDialogFragment : DialogFragment() { } } + isCancelable = dismissible + return builder.show() } @@ -67,6 +75,8 @@ class MessageDialogFragment : DialogFragment() { private const val DESCRIPTION_ID = "DescriptionId" private const val DESCRIPTION_STRING = "DescriptionString" private const val HELP_LINK = "Link" + private const val DISMISSIBLE = "Dismissible" + private const val CLEAR_POSITIVE_ACTION = "ClearPositiveAction" fun newInstance( activity: FragmentActivity? = null, @@ -75,22 +85,28 @@ class MessageDialogFragment : DialogFragment() { descriptionId: Int = 0, descriptionString: String = "", helpLinkId: Int = 0, + dismissible: Boolean = true, positiveAction: (() -> Unit)? = null ): MessageDialogFragment { + var clearPositiveAction = false + if (activity != null) { + ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply { + clear() + this.positiveAction = positiveAction + } + } else { + clearPositiveAction = true + } + val dialog = MessageDialogFragment() - val bundle = Bundle() - bundle.apply { + val bundle = Bundle().apply { putInt(TITLE_ID, titleId) putString(TITLE_STRING, titleString) putInt(DESCRIPTION_ID, descriptionId) putString(DESCRIPTION_STRING, descriptionString) putInt(HELP_LINK, helpLinkId) - } - if (activity != null) { - ViewModelProvider(activity)[MessageDialogViewModel::class.java].apply { - clear() - this.positiveAction = positiveAction - } + putBoolean(DISMISSIBLE, dismissible) + putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction) } dialog.arguments = bundle 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 import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback import com.google.android.material.transition.MaterialFadeThrough import kotlinx.coroutines.launch +import org.yuzu.yuzu_emu.NativeLibrary import java.io.File import org.yuzu.yuzu_emu.R import org.yuzu.yuzu_emu.YuzuApplication @@ -162,7 +163,7 @@ class SetupFragment : Fragment() { R.string.install_prod_keys_warning_help, { val file = File(DirectoryInitialization.userDirectory + "/keys/prod.keys") - if (file.exists()) { + if (file.exists() && NativeLibrary.areKeysPresent()) { StepState.COMPLETE } else { StepState.INCOMPLETE @@ -347,7 +348,8 @@ class SetupFragment : Fragment() { val getProdKey = registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> if (result != null) { - if (mainActivity.processKey(result)) { + mainActivity.processKey(result) + if (NativeLibrary.areKeysPresent()) { keyCallback.onStepCompleted() } } 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() { private val _reloadPropertiesList = MutableStateFlow(false) val reloadPropertiesList get() = _reloadPropertiesList.asStateFlow() + private val _checkKeys = MutableStateFlow(false) + val checkKeys = _checkKeys.asStateFlow() + var navigatedToSetup = false fun setNavigationVisibility(visible: Boolean, animated: Boolean) { @@ -66,4 +69,8 @@ class HomeViewModel : ViewModel() { fun reloadPropertiesList(reload: Boolean) { _reloadPropertiesList.value = reload } + + fun setCheckKeys(value: Boolean) { + _checkKeys.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 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 { override var themeId: Int = 0 + private val CHECKED_DECRYPTION = "CheckedDecryption" + private var checkedDecryption = false + override fun onCreate(savedInstanceState: Bundle?) { val splashScreen = installSplashScreen() splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } @@ -75,6 +78,18 @@ class MainActivity : AppCompatActivity(), ThemeProvider { binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) + if (savedInstanceState != null) { + checkedDecryption = savedInstanceState.getBoolean(CHECKED_DECRYPTION) + } + if (!checkedDecryption) { + val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext) + .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true) + if (!firstTimeSetup) { + checkKeys() + } + checkedDecryption = true + } + WindowCompat.setDecorFitsSystemWindows(window, false) window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) @@ -150,6 +165,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { } } } + launch { + repeatOnLifecycle(Lifecycle.State.CREATED) { + homeViewModel.checkKeys.collect { + if (it) { + checkKeys() + homeViewModel.setCheckKeys(false) + } + } + } + } } // Dismiss previous notifications (should not happen unless a crash occurred) @@ -158,6 +183,21 @@ class MainActivity : AppCompatActivity(), ThemeProvider { setInsets() } + private fun checkKeys() { + if (!NativeLibrary.areKeysPresent()) { + MessageDialogFragment.newInstance( + titleId = R.string.keys_missing, + descriptionId = R.string.keys_missing_description, + helpLinkId = R.string.keys_missing_help + ).show(supportFragmentManager, MessageDialogFragment.TAG) + } + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putBoolean(CHECKED_DECRYPTION, checkedDecryption) + } + fun finishSetup(navController: NavController) { navController.navigate(R.id.action_firstTimeSetupFragment_to_gamesFragment) (binding.navigationView as NavigationBarView).setupWithNavController(navController) @@ -349,6 +389,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { R.string.install_keys_success, Toast.LENGTH_SHORT ).show() + homeViewModel.setCheckKeys(true) gamesViewModel.reloadGames(true) return true } else { @@ -399,6 +440,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { firmwarePath.deleteRecursively() cacheFirmwareDir.copyRecursively(firmwarePath, true) NativeLibrary.initializeSystem(true) + homeViewModel.setCheckKeys(true) getString(R.string.save_file_imported_success) } } 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 }; return static_cast<int>( - ContentManager::InstallNSP(&EmulationSession::GetInstance().System(), - EmulationSession::GetInstance().System().GetFilesystem().get(), + ContentManager::InstallNSP(EmulationSession::GetInstance().System(), + *EmulationSession::GetInstance().System().GetFilesystem(), GetJString(env, j_file), callback)); } @@ -825,7 +825,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeUpdate(JNIEnv* env, jobject job void Java_org_yuzu_yuzu_1emu_NativeLibrary_removeDLC(JNIEnv* env, jobject jobj, jstring jprogramId) { auto program_id = EmulationSession::GetProgramId(env, jprogramId); - ContentManager::RemoveAllDLC(&EmulationSession::GetInstance().System(), program_id); + ContentManager::RemoveAllDLC(EmulationSession::GetInstance().System(), program_id); } void 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, program_id, GetJString(env, jname)); } -jobject Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, jobject jobj, - jobject jcallback) { +jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyInstalledContents(JNIEnv* env, + jobject jobj, + jobject jcallback) { auto jlambdaClass = env->GetObjectClass(jcallback); auto jlambdaInvokeMethod = env->GetMethodID( 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 auto& session = EmulationSession::GetInstance(); std::vector<std::string> result = ContentManager::VerifyInstalledContents( - &session.System(), session.GetContentProvider(), callback); + session.System(), *session.GetContentProvider(), callback); jobjectArray jresult = env->NewObjectArray(result.size(), IDCache::GetStringClass(), ToJString(env, "")); for (size_t i = 0; i < result.size(); ++i) { @@ -869,7 +870,7 @@ jint Java_org_yuzu_yuzu_1emu_NativeLibrary_verifyGameContents(JNIEnv* env, jobje }; auto& session = EmulationSession::GetInstance(); return static_cast<jint>( - ContentManager::VerifyGameContents(&session.System(), GetJString(env, jpath), callback)); + ContentManager::VerifyGameContents(session.System(), GetJString(env, jpath), callback)); } jstring 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, EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); } +jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) { + auto& system = EmulationSession::GetInstance().System(); + system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); + return ContentManager::AreKeysPresent(); +} + } // 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 @@ <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-emu.org/help/quickstart/#dumping-decryption-keys</string> <!-- Applet launcher strings --> <string name="applets">Applet launcher</string> |