diff options
| author | 2023-04-30 22:14:57 -0400 | |
|---|---|---|
| committer | 2023-06-03 00:05:57 -0700 | |
| commit | 912bf6a0c65036ba1d0da03716db77ce26823b82 (patch) | |
| tree | fbe358fe583a24d2117ecda7c2912a9f8ebdce81 /src/android | |
| parent | android: Fix inline keyboard input (diff) | |
| download | yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.gz yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.xz yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.zip | |
android: Add user directory shortcut
Diffstat (limited to 'src/android')
6 files changed, 140 insertions, 25 deletions
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index 4791e3417..ae473ae3a 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | <uses-permission android:name="android.permission.INTERNET" /> | 15 | <uses-permission android:name="android.permission.INTERNET" /> |
| 16 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | 16 | <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> |
| 17 | <uses-permission android:name="android.permission.NFC" /> | 17 | <uses-permission android:name="android.permission.NFC" /> |
| 18 | <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> | ||
| 18 | 19 | ||
| 19 | <application | 20 | <application |
| 20 | android:name="org.yuzu.yuzu_emu.YuzuApplication" | 21 | android:name="org.yuzu.yuzu_emu.YuzuApplication" |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt index f987c6b7b..5848c87c1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt | |||
| @@ -15,23 +15,29 @@ import java.io.File | |||
| 15 | fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir | 15 | fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir |
| 16 | 16 | ||
| 17 | class YuzuApplication : Application() { | 17 | class YuzuApplication : Application() { |
| 18 | private fun createNotificationChannel() { | 18 | private fun createNotificationChannels() { |
| 19 | // Create the NotificationChannel, but only on API 26+ because | 19 | val emulationChannel = NotificationChannel( |
| 20 | // the NotificationChannel class is new and not in the support library | 20 | getString(R.string.emulation_notification_channel_id), |
| 21 | val name: CharSequence = getString(R.string.app_notification_channel_name) | 21 | getString(R.string.emulation_notification_channel_name), |
| 22 | val description = getString(R.string.app_notification_channel_description) | ||
| 23 | val channel = NotificationChannel( | ||
| 24 | getString(R.string.app_notification_channel_id), | ||
| 25 | name, | ||
| 26 | NotificationManager.IMPORTANCE_LOW | 22 | NotificationManager.IMPORTANCE_LOW |
| 27 | ) | 23 | ) |
| 28 | channel.description = description | 24 | emulationChannel.description = getString(R.string.emulation_notification_channel_description) |
| 29 | channel.setSound(null, null) | 25 | emulationChannel.setSound(null, null) |
| 30 | channel.vibrationPattern = null | 26 | emulationChannel.vibrationPattern = null |
| 27 | |||
| 28 | val noticeChannel = NotificationChannel( | ||
| 29 | getString(R.string.notice_notification_channel_id), | ||
| 30 | getString(R.string.notice_notification_channel_name), | ||
| 31 | NotificationManager.IMPORTANCE_HIGH | ||
| 32 | ) | ||
| 33 | noticeChannel.description = getString(R.string.notice_notification_channel_description) | ||
| 34 | noticeChannel.setSound(null, null) | ||
| 35 | |||
| 31 | // Register the channel with the system; you can't change the importance | 36 | // Register the channel with the system; you can't change the importance |
| 32 | // or other notification behaviors after this | 37 | // or other notification behaviors after this |
| 33 | val notificationManager = getSystemService(NotificationManager::class.java) | 38 | val notificationManager = getSystemService(NotificationManager::class.java) |
| 34 | notificationManager.createNotificationChannel(channel) | 39 | notificationManager.createNotificationChannel(emulationChannel) |
| 40 | notificationManager.createNotificationChannel(noticeChannel) | ||
| 35 | } | 41 | } |
| 36 | 42 | ||
| 37 | override fun onCreate() { | 43 | override fun onCreate() { |
| @@ -42,8 +48,7 @@ class YuzuApplication : Application() { | |||
| 42 | GpuDriverHelper.initializeDriverParameters(applicationContext) | 48 | GpuDriverHelper.initializeDriverParameters(applicationContext) |
| 43 | NativeLibrary.logDeviceInfo() | 49 | NativeLibrary.logDeviceInfo() |
| 44 | 50 | ||
| 45 | // TODO(bunnei): Disable notifications until we support app suspension. | 51 | createNotificationChannels(); |
| 46 | //createNotificationChannel(); | ||
| 47 | } | 52 | } |
| 48 | 53 | ||
| 49 | companion object { | 54 | companion object { |
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 23d2da4d0..0e7c181ea 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 | |||
| @@ -3,14 +3,21 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.Manifest | ||
| 7 | import android.content.ActivityNotFoundException | ||
| 6 | import android.content.DialogInterface | 8 | import android.content.DialogInterface |
| 7 | import android.content.Intent | 9 | import android.content.Intent |
| 10 | import android.content.pm.PackageManager | ||
| 8 | import android.os.Bundle | 11 | import android.os.Bundle |
| 12 | import android.provider.DocumentsContract | ||
| 9 | import android.view.LayoutInflater | 13 | import android.view.LayoutInflater |
| 10 | import android.view.View | 14 | import android.view.View |
| 11 | import android.view.ViewGroup | 15 | import android.view.ViewGroup |
| 12 | import android.widget.Toast | 16 | import android.widget.Toast |
| 13 | import androidx.appcompat.app.AppCompatActivity | 17 | import androidx.appcompat.app.AppCompatActivity |
| 18 | import androidx.core.app.ActivityCompat | ||
| 19 | import androidx.core.app.NotificationCompat | ||
| 20 | import androidx.core.app.NotificationManagerCompat | ||
| 14 | import androidx.core.view.ViewCompat | 21 | import androidx.core.view.ViewCompat |
| 15 | import androidx.core.view.WindowInsetsCompat | 22 | import androidx.core.view.WindowInsetsCompat |
| 16 | import androidx.fragment.app.Fragment | 23 | import androidx.fragment.app.Fragment |
| @@ -19,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder | |||
| 19 | import org.yuzu.yuzu_emu.R | 26 | import org.yuzu.yuzu_emu.R |
| 20 | import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter | 27 | import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter |
| 21 | import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding | 28 | import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding |
| 29 | import org.yuzu.yuzu_emu.features.DocumentProvider | ||
| 22 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity | 30 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity |
| 23 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 31 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 24 | import org.yuzu.yuzu_emu.model.HomeSetting | 32 | import org.yuzu.yuzu_emu.model.HomeSetting |
| @@ -50,6 +58,11 @@ class HomeSettingsFragment : Fragment() { | |||
| 50 | R.drawable.ic_settings | 58 | R.drawable.ic_settings |
| 51 | ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }, | 59 | ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }, |
| 52 | HomeSetting( | 60 | HomeSetting( |
| 61 | R.string.open_user_folder, | ||
| 62 | R.string.open_user_folder_description, | ||
| 63 | R.drawable.ic_folder | ||
| 64 | ) { openFileManager() }, | ||
| 65 | HomeSetting( | ||
| 53 | R.string.install_gpu_driver, | 66 | R.string.install_gpu_driver, |
| 54 | R.string.install_gpu_driver_description, | 67 | R.string.install_gpu_driver_description, |
| 55 | R.drawable.ic_input | 68 | R.drawable.ic_input |
| @@ -84,6 +97,82 @@ class HomeSettingsFragment : Fragment() { | |||
| 84 | _binding = null | 97 | _binding = null |
| 85 | } | 98 | } |
| 86 | 99 | ||
| 100 | private fun openFileManager() { | ||
| 101 | // First, try to open the user data folder directly | ||
| 102 | try { | ||
| 103 | startActivity(getFileManagerIntentOnDocumentProvider(Intent.ACTION_VIEW)) | ||
| 104 | return | ||
| 105 | } catch (_: ActivityNotFoundException) {} | ||
| 106 | |||
| 107 | try { | ||
| 108 | startActivity(getFileManagerIntentOnDocumentProvider("android.provider.action.BROWSE")) | ||
| 109 | return | ||
| 110 | } catch (_: ActivityNotFoundException) {} | ||
| 111 | |||
| 112 | // Just try to open the file manager, try the package name used on "normal" phones | ||
| 113 | try { | ||
| 114 | startActivity(getFileManagerIntent("com.google.android.documentsui")) | ||
| 115 | showNoLinkNotification() | ||
| 116 | return | ||
| 117 | } catch (_: ActivityNotFoundException) {} | ||
| 118 | |||
| 119 | try { | ||
| 120 | // Next, try the AOSP package name | ||
| 121 | startActivity(getFileManagerIntent("com.android.documentsui")) | ||
| 122 | showNoLinkNotification() | ||
| 123 | return | ||
| 124 | } catch (_: ActivityNotFoundException) {} | ||
| 125 | |||
| 126 | Toast.makeText( | ||
| 127 | requireContext(), | ||
| 128 | resources.getString(R.string.no_file_manager), | ||
| 129 | Toast.LENGTH_LONG | ||
| 130 | ).show() | ||
| 131 | } | ||
| 132 | |||
| 133 | private fun getFileManagerIntent(packageName: String): Intent { | ||
| 134 | // Fragile, but some phones don't expose the system file manager in any better way | ||
| 135 | val intent = Intent(Intent.ACTION_MAIN) | ||
| 136 | intent.setClassName(packageName, "com.android.documentsui.files.FilesActivity") | ||
| 137 | intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK | ||
| 138 | return intent | ||
| 139 | } | ||
| 140 | |||
| 141 | private fun getFileManagerIntentOnDocumentProvider(action: String): Intent { | ||
| 142 | val authority = "${requireContext().packageName}.user" | ||
| 143 | val intent = Intent(action) | ||
| 144 | intent.addCategory(Intent.CATEGORY_DEFAULT) | ||
| 145 | intent.data = DocumentsContract.buildRootUri(authority, DocumentProvider.ROOT_ID) | ||
| 146 | intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) | ||
| 147 | return intent | ||
| 148 | } | ||
| 149 | |||
| 150 | private fun showNoLinkNotification() { | ||
| 151 | val builder = NotificationCompat.Builder(requireContext(), getString(R.string.notice_notification_channel_id)) | ||
| 152 | .setSmallIcon(R.drawable.ic_stat_notification_logo) | ||
| 153 | .setContentTitle(getString(R.string.notification_no_directory_link)) | ||
| 154 | .setContentText(getString(R.string.notification_no_directory_link_description)) | ||
| 155 | .setPriority(NotificationCompat.PRIORITY_HIGH) | ||
| 156 | .setAutoCancel(true) | ||
| 157 | // TODO: Make the click action for this notification lead to a help article | ||
| 158 | |||
| 159 | with(NotificationManagerCompat.from(requireContext())) { | ||
| 160 | if (ActivityCompat.checkSelfPermission( | ||
| 161 | requireContext(), | ||
| 162 | Manifest.permission.POST_NOTIFICATIONS | ||
| 163 | ) != PackageManager.PERMISSION_GRANTED | ||
| 164 | ) { | ||
| 165 | Toast.makeText( | ||
| 166 | requireContext(), | ||
| 167 | resources.getString(R.string.notification_permission_not_granted), | ||
| 168 | Toast.LENGTH_LONG | ||
| 169 | ).show() | ||
| 170 | return | ||
| 171 | } | ||
| 172 | notify(0, builder.build()) | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 87 | private fun driverInstaller() { | 176 | private fun driverInstaller() { |
| 88 | // Get the driver name for the dialog message. | 177 | // Get the driver name for the dialog message. |
| 89 | var driverName = GpuDriverHelper.customDriverName | 178 | var driverName = GpuDriverHelper.customDriverName |
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 2af78b02c..3d2f8719c 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 | |||
| @@ -4,11 +4,13 @@ | |||
| 4 | package org.yuzu.yuzu_emu.fragments | 4 | package org.yuzu.yuzu_emu.fragments |
| 5 | 5 | ||
| 6 | import android.content.Intent | 6 | import android.content.Intent |
| 7 | import android.os.Build | ||
| 7 | import android.os.Bundle | 8 | import android.os.Bundle |
| 8 | import android.view.LayoutInflater | 9 | import android.view.LayoutInflater |
| 9 | import android.view.View | 10 | import android.view.View |
| 10 | import android.view.ViewGroup | 11 | import android.view.ViewGroup |
| 11 | import androidx.activity.OnBackPressedCallback | 12 | import androidx.activity.OnBackPressedCallback |
| 13 | import androidx.activity.result.contract.ActivityResultContracts | ||
| 12 | import androidx.appcompat.app.AppCompatActivity | 14 | import androidx.appcompat.app.AppCompatActivity |
| 13 | import androidx.core.content.ContextCompat | 15 | import androidx.core.content.ContextCompat |
| 14 | import androidx.core.view.ViewCompat | 16 | import androidx.core.view.ViewCompat |
| @@ -63,6 +65,10 @@ class SetupFragment : Fragment() { | |||
| 63 | } | 65 | } |
| 64 | 66 | ||
| 65 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { | 67 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { |
| 68 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||
| 69 | pushNotificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS) | ||
| 70 | } | ||
| 71 | |||
| 66 | mainActivity = requireActivity() as MainActivity | 72 | mainActivity = requireActivity() as MainActivity |
| 67 | 73 | ||
| 68 | homeViewModel.setNavigationVisibility(false) | 74 | homeViewModel.setNavigationVisibility(false) |
| @@ -219,6 +225,11 @@ class SetupFragment : Fragment() { | |||
| 219 | _binding = null | 225 | _binding = null |
| 220 | } | 226 | } |
| 221 | 227 | ||
| 228 | private val pushNotificationPermissionLauncher = | ||
| 229 | registerForActivityResult(ActivityResultContracts.RequestPermission()) { | ||
| 230 | // TODO: Show proper notification request reason and confirmation | ||
| 231 | } | ||
| 232 | |||
| 222 | private fun finishSetup() { | 233 | private fun finishSetup() { |
| 223 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit() | 234 | PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit() |
| 224 | .putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false) | 235 | .putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt index 557fe0738..7e33ff044 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt | |||
| @@ -29,10 +29,10 @@ class ForegroundService : Service() { | |||
| 29 | PendingIntent.FLAG_IMMUTABLE | 29 | PendingIntent.FLAG_IMMUTABLE |
| 30 | ) | 30 | ) |
| 31 | val builder = | 31 | val builder = |
| 32 | NotificationCompat.Builder(this, getString(R.string.app_notification_channel_id)) | 32 | NotificationCompat.Builder(this, getString(R.string.emulation_notification_channel_id)) |
| 33 | .setSmallIcon(R.drawable.ic_stat_notification_logo) | 33 | .setSmallIcon(R.drawable.ic_stat_notification_logo) |
| 34 | .setContentTitle(getString(R.string.app_name)) | 34 | .setContentTitle(getString(R.string.app_name)) |
| 35 | .setContentText(getString(R.string.app_notification_running)) | 35 | .setContentText(getString(R.string.emulation_notification_running)) |
| 36 | .setPriority(NotificationCompat.PRIORITY_LOW) | 36 | .setPriority(NotificationCompat.PRIORITY_LOW) |
| 37 | .setOngoing(true) | 37 | .setOngoing(true) |
| 38 | .setVibrate(null) | 38 | .setVibrate(null) |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 8220cd412..58ae37790 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -4,10 +4,14 @@ | |||
| 4 | <!-- General application strings --> | 4 | <!-- General application strings --> |
| 5 | <string name="app_name" translatable="false">yuzu</string> | 5 | <string name="app_name" translatable="false">yuzu</string> |
| 6 | <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.<br /><br />Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.<br /><br /><![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string> | 6 | <string name="app_disclaimer">This software will run games for the Nintendo Switch game console. No game titles or keys are included.<br /><br />Before you begin, please locate your <![CDATA[<b> prod.keys </b>]]> file on your device storage.<br /><br /><![CDATA[<a href="https://yuzu-emu.org/help/quickstart">Learn more</a>]]></string> |
| 7 | <string name="app_notification_channel_name" translatable="false">yuzu</string> | 7 | <string name="emulation_notification_channel_name">Emulation is Active</string> |
| 8 | <string name="app_notification_channel_id" translatable="false">yuzu</string> | 8 | <string name="emulation_notification_channel_id" translatable="false">emulationIsActive</string> |
| 9 | <string name="app_notification_channel_description">yuzu Switch emulator notifications</string> | 9 | <string name="emulation_notification_channel_description">Shows a persistent notification when emulation is running.</string> |
| 10 | <string name="app_notification_running">yuzu is running</string> | 10 | <string name="emulation_notification_running">yuzu is running</string> |
| 11 | <string name="notice_notification_channel_name">Notices and errors</string> | ||
| 12 | <string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string> | ||
| 13 | <string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string> | ||
| 14 | <string name="notification_permission_not_granted">Notification permission not granted!</string> | ||
| 11 | 15 | ||
| 12 | <!-- Setup strings --> | 16 | <!-- Setup strings --> |
| 13 | <string name="welcome">Welcome!</string> | 17 | <string name="welcome">Welcome!</string> |
| @@ -29,14 +33,14 @@ | |||
| 29 | <!-- Home strings --> | 33 | <!-- Home strings --> |
| 30 | <string name="home_games">Games</string> | 34 | <string name="home_games">Games</string> |
| 31 | <string name="home_settings">Settings</string> | 35 | <string name="home_settings">Settings</string> |
| 32 | <string name="select_games_folder">Select Games Folder</string> | 36 | <string name="select_games_folder">Select games folder</string> |
| 33 | <string name="select_games_folder_description">Allows yuzu to populate the games list</string> | 37 | <string name="select_games_folder_description">Allows yuzu to populate the games list</string> |
| 34 | <string name="add_games_warning">Skip selecting games folder?</string> | 38 | <string name="add_games_warning">Skip selecting games folder?</string> |
| 35 | <string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string> | 39 | <string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string> |
| 36 | <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string> | 40 | <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string> |
| 37 | <string name="home_search_games">Search Games</string> | 41 | <string name="home_search_games">Search Games</string> |
| 38 | <string name="games_dir_selected">Games directory selected</string> | 42 | <string name="games_dir_selected">Games directory selected</string> |
| 39 | <string name="install_prod_keys">Install Prod.keys</string> | 43 | <string name="install_prod_keys">Install prod.keys</string> |
| 40 | <string name="install_prod_keys_description">Required to decrypt retail games</string> | 44 | <string name="install_prod_keys_description">Required to decrypt retail games</string> |
| 41 | <string name="install_prod_keys_warning">Skip adding keys?</string> | 45 | <string name="install_prod_keys_warning">Skip adding keys?</string> |
| 42 | <string name="install_prod_keys_warning_description">Valid keys are required to emulate retail games. Only homebrew apps will function if you continue.</string> | 46 | <string name="install_prod_keys_warning_description">Valid keys are required to emulate retail games. Only homebrew apps will function if you continue.</string> |
| @@ -44,16 +48,21 @@ | |||
| 44 | <string name="warning_help">Help</string> | 48 | <string name="warning_help">Help</string> |
| 45 | <string name="warning_skip">Skip</string> | 49 | <string name="warning_skip">Skip</string> |
| 46 | <string name="warning_cancel">Cancel</string> | 50 | <string name="warning_cancel">Cancel</string> |
| 47 | <string name="install_amiibo_keys">Install Amiibo Keys</string> | 51 | <string name="install_amiibo_keys">Install Amiibo keys</string> |
| 48 | <string name="install_amiibo_keys_description">Required to use Amiibo in game</string> | 52 | <string name="install_amiibo_keys_description">Required to use Amiibo in game</string> |
| 49 | <string name="invalid_keys_file">Invalid keys file selected</string> | 53 | <string name="invalid_keys_file">Invalid keys file selected</string> |
| 50 | <string name="install_keys_success">Keys successfully installed</string> | 54 | <string name="install_keys_success">Keys successfully installed</string> |
| 51 | <string name="install_keys_failure">Keys file (prod.keys) is invalid</string> | 55 | <string name="install_keys_failure">Keys file (prod.keys) is invalid</string> |
| 52 | <string name="install_amiibo_keys_failure">Keys file (key_retail.bin) is invalid</string> | 56 | <string name="install_amiibo_keys_failure">Keys file (key_retail.bin) is invalid</string> |
| 53 | <string name="install_gpu_driver">Install GPU Driver</string> | 57 | <string name="install_gpu_driver">Install GPU driver</string> |
| 54 | <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string> | 58 | <string name="install_gpu_driver_description">Install alternative drivers for potentially better performance or accuracy</string> |
| 55 | <string name="advanced_settings">Advanced Settings</string> | 59 | <string name="advanced_settings">Advanced settings</string> |
| 56 | <string name="settings_description">Configure emulator settings</string> | 60 | <string name="settings_description">Configure emulator settings</string> |
| 61 | <string name="open_user_folder">Open yuzu folder</string> | ||
| 62 | <string name="open_user_folder_description">Manage yuzu\'s internal files</string> | ||
| 63 | <string name="no_file_manager">No file manager found</string> | ||
| 64 | <string name="notification_no_directory_link">Couldn\'t open yuzu directory</string> | ||
| 65 | <string name="notification_no_directory_link_description">Please locate the user folder with the file manager\'s side panel manually.</string> | ||
| 57 | 66 | ||
| 58 | <!-- General settings strings --> | 67 | <!-- General settings strings --> |
| 59 | <string name="frame_limit_enable">Enable limit speed</string> | 68 | <string name="frame_limit_enable">Enable limit speed</string> |