From 20abd49a21e977d0ca3f2175b5ae9ce4a5ea4bff Mon Sep 17 00:00:00 2001
From: Charles Lombardo <clombardo169@gmail.com>
Date: Thu, 1 Jun 2023 14:16:57 -0400
Subject: [PATCH] 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 @@
     <string name="install_amiibo_keys_description">Required to use Amiibo in game</string>
     <string name="invalid_keys_file">Invalid keys file selected</string>
     <string name="install_keys_success">Keys successfully installed</string>
-    <string name="install_keys_failure">Keys file (prod.keys) is invalid</string>
-    <string name="install_amiibo_keys_failure">Keys file (key_retail.bin) is invalid</string>
+    <string name="reading_keys_failure">Error reading encryption keys</string>
+    <string name="install_keys_failure_extension_description">
+        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.
+    </string>
+    <string name="invalid_keys_error">Invalid encryption keys</string>
+    <string name="dumping_keys_quickstart_link">https://yuzu-emu.org/help/quickstart/#dumping-decryption-keys</string>
+    <string name="install_keys_failure_description">The selected file is incorrect or corrupt. Please redump your keys.</string>
     <string name="install_gpu_driver">Install GPU driver</string>
     <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string>
     <string name="advanced_settings">Advanced settings</string>
@@ -164,6 +171,8 @@
     <string name="reset_all_settings">Reset all settings?</string>
     <string name="reset_all_settings_description">All Advanced Settings will be reset to their default configuration. This can not be undone.</string>
     <string name="settings_reset">Settings reset</string>
+    <string name="close">Close</string>
+    <string name="learn_more">Learn More</string>
 
     <!-- GPU driver installation -->
     <string name="select_gpu_driver">Select GPU driver</string>