diff options
6 files changed, 67 insertions, 2 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 c408485c6..0fb35bf98 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 | |||
| @@ -615,6 +615,11 @@ object NativeLibrary { | |||
| 615 | external fun clearFilesystemProvider() | 615 | external fun clearFilesystemProvider() |
| 616 | 616 | ||
| 617 | /** | 617 | /** |
| 618 | * Checks if all necessary keys are present for decryption | ||
| 619 | */ | ||
| 620 | external fun areKeysPresent(): Boolean | ||
| 621 | |||
| 622 | /** | ||
| 618 | * Button type for use in onTouchEvent | 623 | * Button type for use in onTouchEvent |
| 619 | */ | 624 | */ |
| 620 | object ButtonType { | 625 | object ButtonType { |
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 | |||
| 31 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback | 31 | import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback |
| 32 | import com.google.android.material.transition.MaterialFadeThrough | 32 | import com.google.android.material.transition.MaterialFadeThrough |
| 33 | import kotlinx.coroutines.launch | 33 | import kotlinx.coroutines.launch |
| 34 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 34 | import java.io.File | 35 | import java.io.File |
| 35 | import org.yuzu.yuzu_emu.R | 36 | import org.yuzu.yuzu_emu.R |
| 36 | import org.yuzu.yuzu_emu.YuzuApplication | 37 | import 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 4c3644cc5..e51453eca 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -913,4 +913,10 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_clearFilesystemProvider(JNIEnv* env, | |||
| 913 | EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); | 913 | EmulationSession::GetInstance().GetContentProvider()->ClearAllEntries(); |
| 914 | } | 914 | } |
| 915 | 915 | ||
| 916 | jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_areKeysPresent(JNIEnv* env, jobject jobj) { | ||
| 917 | auto& system = EmulationSession::GetInstance().System(); | ||
| 918 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); | ||
| 919 | return ContentManager::AreKeysPresent(); | ||
| 920 | } | ||
| 921 | |||
| 916 | } // extern "C" | 922 | } // 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> |