Merge pull request #12777 from t895/firmware-warning

android: Add key warning
This commit is contained in:
liamwhite 2024-01-25 16:21:29 -05:00 committed by GitHub
commit 3e2d3548f2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 146 additions and 173 deletions

View file

@ -619,6 +619,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
*/

View file

@ -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 {
val dialog = MessageDialogFragment()
val bundle = Bundle()
bundle.apply {
putInt(TITLE_ID, titleId)
putString(TITLE_STRING, titleString)
putInt(DESCRIPTION_ID, descriptionId)
putString(DESCRIPTION_STRING, descriptionString)
putInt(HELP_LINK, helpLinkId)
}
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().apply {
putInt(TITLE_ID, titleId)
putString(TITLE_STRING, titleString)
putInt(DESCRIPTION_ID, descriptionId)
putString(DESCRIPTION_STRING, descriptionString)
putInt(HELP_LINK, helpLinkId)
putBoolean(DISMISSIBLE, dismissible)
putBoolean(CLEAR_POSITIVE_ACTION, clearPositiveAction)
}
dialog.arguments = bundle
return dialog

View file

@ -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()
}
}

View file

@ -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
}
}

View file

@ -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) {

View file

@ -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"

View file

@ -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>