From c2d150b4aee0454270ba716f4862bd5b363b6fec Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Thu, 1 Jun 2023 14:16:57 -0400 Subject: [PATCH 1/3] android: Warning dialogs for key errors --- .../fragments/MessageDialogFragment.kt | 62 +++++++++++++++++++ .../org/yuzu/yuzu_emu/ui/main/MainActivity.kt | 51 +++++++-------- .../app/src/main/res/values/strings.xml | 13 +++- 3 files changed, 95 insertions(+), 31 deletions(-) create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt 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 new file mode 100644 index 0000000000..2db38fdc2e --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/MessageDialogFragment.kt @@ -0,0 +1,62 @@ +// SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.yuzu.yuzu_emu.fragments + +import android.app.Dialog +import android.content.Intent +import android.net.Uri +import android.os.Bundle +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import org.yuzu.yuzu_emu.R + +class MessageDialogFragment : DialogFragment() { + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val titleId = requireArguments().getInt(TITLE) + val descriptionId = requireArguments().getInt(DESCRIPTION) + val helpLinkId = requireArguments().getInt(HELP_LINK) + + val dialog = MaterialAlertDialogBuilder(requireContext()) + .setPositiveButton(R.string.close, null) + .setTitle(titleId) + .setMessage(descriptionId) + + if (helpLinkId != 0) { + dialog.setNeutralButton(R.string.learn_more) { _, _ -> + openLink(getString(helpLinkId)) + } + } + + return dialog.show() + } + + private fun openLink(link: String) { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(link)) + startActivity(intent) + } + + companion object { + const val TAG = "MessageDialogFragment" + + private const val TITLE = "Title" + private const val DESCRIPTION = "Description" + private const val HELP_LINK = "Link" + + fun newInstance( + titleId: Int, + descriptionId: Int, + helpLinkId: Int = 0 + ): MessageDialogFragment { + val dialog = MessageDialogFragment() + val bundle = Bundle() + bundle.apply { + putInt(TITLE, titleId) + putInt(DESCRIPTION, descriptionId) + putInt(HELP_LINK, helpLinkId) + } + dialog.arguments = bundle + return dialog + } + } +} 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 b1329db74c..f8bca11bb6 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 @@ -37,6 +37,7 @@ import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile +import org.yuzu.yuzu_emu.fragments.MessageDialogFragment import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.utils.* @@ -251,11 +252,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider { if (result == null) return@registerForActivityResult - val takeFlags = - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION contentResolver.takePersistableUriPermission( result, - takeFlags + Intent.FLAG_GRANT_READ_URI_PERMISSION ) // When a new directory is picked, we currently will reset the existing games @@ -279,19 +278,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { return@registerForActivityResult if (!FileUtil.hasExtension(result.toString(), "keys")) { - Toast.makeText( - applicationContext, - R.string.invalid_keys_file, - Toast.LENGTH_SHORT - ).show() + MessageDialogFragment.newInstance( + R.string.reading_keys_failure, + R.string.install_keys_failure_extension_description + ).show(supportFragmentManager, MessageDialogFragment.TAG) return@registerForActivityResult } - val takeFlags = - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION contentResolver.takePersistableUriPermission( result, - takeFlags + Intent.FLAG_GRANT_READ_URI_PERMISSION ) val dstPath = DirectoryInitialization.userDirectory + "/keys/" @@ -310,11 +306,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider { ).show() gamesViewModel.reloadGames(true) } else { - Toast.makeText( - applicationContext, - R.string.install_keys_failure, - Toast.LENGTH_LONG - ).show() + MessageDialogFragment.newInstance( + R.string.invalid_keys_error, + R.string.install_keys_failure_description, + R.string.dumping_keys_quickstart_link + ).show(supportFragmentManager, MessageDialogFragment.TAG) } } } @@ -325,19 +321,16 @@ class MainActivity : AppCompatActivity(), ThemeProvider { return@registerForActivityResult if (!FileUtil.hasExtension(result.toString(), "bin")) { - Toast.makeText( - applicationContext, - R.string.invalid_keys_file, - Toast.LENGTH_SHORT - ).show() + MessageDialogFragment.newInstance( + R.string.reading_keys_failure, + R.string.install_keys_failure_extension_description + ).show(supportFragmentManager, MessageDialogFragment.TAG) return@registerForActivityResult } - val takeFlags = - Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION contentResolver.takePersistableUriPermission( result, - takeFlags + Intent.FLAG_GRANT_READ_URI_PERMISSION ) val dstPath = DirectoryInitialization.userDirectory + "/keys/" @@ -355,11 +348,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider { Toast.LENGTH_SHORT ).show() } else { - Toast.makeText( - applicationContext, - R.string.install_amiibo_keys_failure, - Toast.LENGTH_LONG - ).show() + MessageDialogFragment.newInstance( + R.string.invalid_keys_error, + R.string.install_keys_failure_description, + R.string.dumping_keys_quickstart_link + ).show(supportFragmentManager, MessageDialogFragment.TAG) } } } diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5e44551ad0..afc681feda 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -64,8 +64,15 @@ Required to use Amiibo in game Invalid keys file selected Keys successfully installed - Keys file (prod.keys) is invalid - Keys file (key_retail.bin) is invalid + Error reading encryption keys + + 1. Verify your keys have the .keys extension.\n\n + 2. Keys must not be stored in the Downloads folder.\n\n + Resolve the issue(s) and try again. + + Invalid encryption keys + https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys + The selected file is incorrect or corrupt. Please redump your keys. Install GPU driver Install alternative drivers for potentially better performance or accuracy Advanced settings @@ -164,6 +171,8 @@ Reset all settings? All Advanced Settings will be reset to their default configuration. This can not be undone. Settings reset + Close + Learn More Select GPU driver From 47c3c2fc35ad16571ad5a978e5b16700590d7285 Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Thu, 1 Jun 2023 23:56:14 -0400 Subject: [PATCH 2/3] android: Adjust import/export saves dialog --- .../fragments/HomeSettingsFragment.kt | 2 +- .../fragments/ImportExportSavesFragment.kt | 24 +++++++++++-------- .../app/src/main/res/values/strings.xml | 10 ++++---- 3 files changed, 21 insertions(+), 15 deletions(-) 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 7cd2409df7..67bcf8491a 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 @@ -99,7 +99,7 @@ class HomeSettingsFragment : Fragment() { R.drawable.ic_add ) { mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }, HomeSetting( - R.string.import_export_saves, + R.string.manage_save_data, R.string.import_export_saves_description, R.drawable.ic_save ) { ImportExportSavesFragment().show(parentFragmentManager, ImportExportSavesFragment.TAG) }, diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt index 6f5068bb58..7a990d0cc8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt @@ -68,19 +68,21 @@ class ImportExportSavesFragment : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { return if (savesFolderRoot == "") { MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.import_export_saves) + .setTitle(R.string.manage_save_data) .setMessage(R.string.import_export_saves_no_profile) .setPositiveButton(android.R.string.ok, null) .show() } else { MaterialAlertDialogBuilder(requireContext()) - .setTitle(R.string.import_export_saves) - .setPositiveButton(R.string.export_saves) { _, _ -> + .setTitle(R.string.manage_save_data) + .setMessage(R.string.manage_save_data_description) + .setNegativeButton(R.string.export_saves) { _, _ -> exportSave() } - .setNeutralButton(R.string.import_saves) { _, _ -> + .setPositiveButton(R.string.import_saves) { _, _ -> documentPicker.launch(arrayOf("application/zip")) } + .setNeutralButton(android.R.string.cancel, null) .show() } } @@ -95,7 +97,10 @@ class ImportExportSavesFragment : DialogFragment() { tempFolder.mkdirs() val saveFolder = File(savesFolderRoot) val outputZipFile = File( - tempFolder, "yuzu saves - ${LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))}.zip" + tempFolder, + "yuzu saves - ${ + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) + }.zip" ) outputZipFile.createNewFile() ZipOutputStream(BufferedOutputStream(FileOutputStream(outputZipFile))).use { zos -> @@ -206,11 +211,10 @@ class ImportExportSavesFragment : DialogFragment() { withContext(Dispatchers.Main) { if (!validZip) { - Toast.makeText( - context, - context.getString(R.string.save_file_invalid_zip_structure), - Toast.LENGTH_LONG - ).show() + MessageDialogFragment.newInstance( + R.string.save_file_invalid_zip_structure, + R.string.save_file_invalid_zip_structure_description + ).show(childFragmentManager, MessageDialogFragment.TAG) return@withContext } Toast.makeText( diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index afc681feda..5fd9aa8f8b 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -87,11 +87,13 @@ No file manager found Could not open yuzu directory Please locate the user folder with the file manager\'s side panel manually. - Import/export saves + Manage save data + Save data found. Please select an option below. Import or export save files - No user profile found. Please launch a game first and retry. - Save files were imported successfully - Invalid save directory structure: The first subfolder name must be the title ID of the game. + No save data found. Please launch a game and retry. + Imported successfully + Invalid save directory structure + The first subfolder name must be the title ID of the game. Import Export From ebbe4d20d4e0a36bc9deab3dbad5177a9b5a0d93 Mon Sep 17 00:00:00 2001 From: Charles Lombardo Date: Thu, 1 Jun 2023 23:57:44 -0400 Subject: [PATCH 3/3] android: Rename "Input Overlay" to "Overlay Options" --- src/android/app/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5fd9aa8f8b..fc24e27f5c 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -222,7 +222,7 @@ Edit Overlay Pause Emulation Unpause Emulation - Input Overlay + Overlay Options Game loading… Loading Settings…