mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 08:59:03 -06:00 
			
		
		
		
	android: Add user directory shortcut
This commit is contained in:
		@@ -15,6 +15,7 @@
 | 
			
		||||
    <uses-permission android:name="android.permission.INTERNET" />
 | 
			
		||||
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
 | 
			
		||||
    <uses-permission android:name="android.permission.NFC" />
 | 
			
		||||
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
 | 
			
		||||
 | 
			
		||||
    <application
 | 
			
		||||
        android:name="org.yuzu.yuzu_emu.YuzuApplication"
 | 
			
		||||
 
 | 
			
		||||
@@ -15,23 +15,29 @@ import java.io.File
 | 
			
		||||
fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir
 | 
			
		||||
 | 
			
		||||
class YuzuApplication : Application() {
 | 
			
		||||
    private fun createNotificationChannel() {
 | 
			
		||||
        // Create the NotificationChannel, but only on API 26+ because
 | 
			
		||||
        // the NotificationChannel class is new and not in the support library
 | 
			
		||||
        val name: CharSequence = getString(R.string.app_notification_channel_name)
 | 
			
		||||
        val description = getString(R.string.app_notification_channel_description)
 | 
			
		||||
        val channel = NotificationChannel(
 | 
			
		||||
            getString(R.string.app_notification_channel_id),
 | 
			
		||||
            name,
 | 
			
		||||
    private fun createNotificationChannels() {
 | 
			
		||||
        val emulationChannel = NotificationChannel(
 | 
			
		||||
            getString(R.string.emulation_notification_channel_id),
 | 
			
		||||
            getString(R.string.emulation_notification_channel_name),
 | 
			
		||||
            NotificationManager.IMPORTANCE_LOW
 | 
			
		||||
        )
 | 
			
		||||
        channel.description = description
 | 
			
		||||
        channel.setSound(null, null)
 | 
			
		||||
        channel.vibrationPattern = null
 | 
			
		||||
        emulationChannel.description = getString(R.string.emulation_notification_channel_description)
 | 
			
		||||
        emulationChannel.setSound(null, null)
 | 
			
		||||
        emulationChannel.vibrationPattern = null
 | 
			
		||||
 | 
			
		||||
        val noticeChannel = NotificationChannel(
 | 
			
		||||
            getString(R.string.notice_notification_channel_id),
 | 
			
		||||
            getString(R.string.notice_notification_channel_name),
 | 
			
		||||
            NotificationManager.IMPORTANCE_HIGH
 | 
			
		||||
        )
 | 
			
		||||
        noticeChannel.description = getString(R.string.notice_notification_channel_description)
 | 
			
		||||
        noticeChannel.setSound(null, null)
 | 
			
		||||
 | 
			
		||||
        // Register the channel with the system; you can't change the importance
 | 
			
		||||
        // or other notification behaviors after this
 | 
			
		||||
        val notificationManager = getSystemService(NotificationManager::class.java)
 | 
			
		||||
        notificationManager.createNotificationChannel(channel)
 | 
			
		||||
        notificationManager.createNotificationChannel(emulationChannel)
 | 
			
		||||
        notificationManager.createNotificationChannel(noticeChannel)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreate() {
 | 
			
		||||
@@ -42,8 +48,7 @@ class YuzuApplication : Application() {
 | 
			
		||||
        GpuDriverHelper.initializeDriverParameters(applicationContext)
 | 
			
		||||
        NativeLibrary.logDeviceInfo()
 | 
			
		||||
 | 
			
		||||
        // TODO(bunnei): Disable notifications until we support app suspension.
 | 
			
		||||
        //createNotificationChannel();
 | 
			
		||||
        createNotificationChannels();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
 
 | 
			
		||||
@@ -3,14 +3,21 @@
 | 
			
		||||
 | 
			
		||||
package org.yuzu.yuzu_emu.fragments
 | 
			
		||||
 | 
			
		||||
import android.Manifest
 | 
			
		||||
import android.content.ActivityNotFoundException
 | 
			
		||||
import android.content.DialogInterface
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.content.pm.PackageManager
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.provider.DocumentsContract
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.Toast
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.core.app.ActivityCompat
 | 
			
		||||
import androidx.core.app.NotificationCompat
 | 
			
		||||
import androidx.core.app.NotificationManagerCompat
 | 
			
		||||
import androidx.core.view.ViewCompat
 | 
			
		||||
import androidx.core.view.WindowInsetsCompat
 | 
			
		||||
import androidx.fragment.app.Fragment
 | 
			
		||||
@@ -19,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
 | 
			
		||||
import org.yuzu.yuzu_emu.R
 | 
			
		||||
import org.yuzu.yuzu_emu.adapters.HomeSettingAdapter
 | 
			
		||||
import org.yuzu.yuzu_emu.databinding.FragmentHomeSettingsBinding
 | 
			
		||||
import org.yuzu.yuzu_emu.features.DocumentProvider
 | 
			
		||||
import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
 | 
			
		||||
import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
 | 
			
		||||
import org.yuzu.yuzu_emu.model.HomeSetting
 | 
			
		||||
@@ -49,6 +57,11 @@ class HomeSettingsFragment : Fragment() {
 | 
			
		||||
                R.string.settings_description,
 | 
			
		||||
                R.drawable.ic_settings
 | 
			
		||||
            ) { SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") },
 | 
			
		||||
            HomeSetting(
 | 
			
		||||
                R.string.open_user_folder,
 | 
			
		||||
                R.string.open_user_folder_description,
 | 
			
		||||
                R.drawable.ic_folder
 | 
			
		||||
            ) { openFileManager() },
 | 
			
		||||
            HomeSetting(
 | 
			
		||||
                R.string.install_gpu_driver,
 | 
			
		||||
                R.string.install_gpu_driver_description,
 | 
			
		||||
@@ -84,6 +97,82 @@ class HomeSettingsFragment : Fragment() {
 | 
			
		||||
        _binding = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun openFileManager() {
 | 
			
		||||
        // First, try to open the user data folder directly
 | 
			
		||||
        try {
 | 
			
		||||
            startActivity(getFileManagerIntentOnDocumentProvider(Intent.ACTION_VIEW))
 | 
			
		||||
            return
 | 
			
		||||
        } catch (_: ActivityNotFoundException) {}
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            startActivity(getFileManagerIntentOnDocumentProvider("android.provider.action.BROWSE"))
 | 
			
		||||
            return
 | 
			
		||||
        } catch (_: ActivityNotFoundException) {}
 | 
			
		||||
 | 
			
		||||
        // Just try to open the file manager, try the package name used on "normal" phones
 | 
			
		||||
        try {
 | 
			
		||||
            startActivity(getFileManagerIntent("com.google.android.documentsui"))
 | 
			
		||||
            showNoLinkNotification()
 | 
			
		||||
            return
 | 
			
		||||
        } catch (_: ActivityNotFoundException) {}
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            // Next, try the AOSP package name
 | 
			
		||||
            startActivity(getFileManagerIntent("com.android.documentsui"))
 | 
			
		||||
            showNoLinkNotification()
 | 
			
		||||
            return
 | 
			
		||||
        } catch (_: ActivityNotFoundException) {}
 | 
			
		||||
 | 
			
		||||
        Toast.makeText(
 | 
			
		||||
            requireContext(),
 | 
			
		||||
            resources.getString(R.string.no_file_manager),
 | 
			
		||||
            Toast.LENGTH_LONG
 | 
			
		||||
        ).show()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getFileManagerIntent(packageName: String): Intent {
 | 
			
		||||
        // Fragile, but some phones don't expose the system file manager in any better way
 | 
			
		||||
        val intent = Intent(Intent.ACTION_MAIN)
 | 
			
		||||
        intent.setClassName(packageName, "com.android.documentsui.files.FilesActivity")
 | 
			
		||||
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
 | 
			
		||||
        return intent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getFileManagerIntentOnDocumentProvider(action: String): Intent {
 | 
			
		||||
        val authority = "${requireContext().packageName}.user"
 | 
			
		||||
        val intent = Intent(action)
 | 
			
		||||
        intent.addCategory(Intent.CATEGORY_DEFAULT)
 | 
			
		||||
        intent.data = DocumentsContract.buildRootUri(authority, DocumentProvider.ROOT_ID)
 | 
			
		||||
        intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
 | 
			
		||||
        return intent
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun showNoLinkNotification() {
 | 
			
		||||
        val builder = NotificationCompat.Builder(requireContext(), getString(R.string.notice_notification_channel_id))
 | 
			
		||||
            .setSmallIcon(R.drawable.ic_stat_notification_logo)
 | 
			
		||||
            .setContentTitle(getString(R.string.notification_no_directory_link))
 | 
			
		||||
            .setContentText(getString(R.string.notification_no_directory_link_description))
 | 
			
		||||
            .setPriority(NotificationCompat.PRIORITY_HIGH)
 | 
			
		||||
            .setAutoCancel(true)
 | 
			
		||||
        // TODO: Make the click action for this notification lead to a help article
 | 
			
		||||
 | 
			
		||||
        with(NotificationManagerCompat.from(requireContext())) {
 | 
			
		||||
            if (ActivityCompat.checkSelfPermission(
 | 
			
		||||
                    requireContext(),
 | 
			
		||||
                    Manifest.permission.POST_NOTIFICATIONS
 | 
			
		||||
                ) != PackageManager.PERMISSION_GRANTED
 | 
			
		||||
            ) {
 | 
			
		||||
                Toast.makeText(
 | 
			
		||||
                    requireContext(),
 | 
			
		||||
                    resources.getString(R.string.notification_permission_not_granted),
 | 
			
		||||
                    Toast.LENGTH_LONG
 | 
			
		||||
                ).show()
 | 
			
		||||
                return
 | 
			
		||||
            }
 | 
			
		||||
            notify(0, builder.build())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun driverInstaller() {
 | 
			
		||||
        // Get the driver name for the dialog message.
 | 
			
		||||
        var driverName = GpuDriverHelper.customDriverName
 | 
			
		||||
 
 | 
			
		||||
@@ -4,11 +4,13 @@
 | 
			
		||||
package org.yuzu.yuzu_emu.fragments
 | 
			
		||||
 | 
			
		||||
import android.content.Intent
 | 
			
		||||
import android.os.Build
 | 
			
		||||
import android.os.Bundle
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import androidx.activity.OnBackPressedCallback
 | 
			
		||||
import androidx.activity.result.contract.ActivityResultContracts
 | 
			
		||||
import androidx.appcompat.app.AppCompatActivity
 | 
			
		||||
import androidx.core.content.ContextCompat
 | 
			
		||||
import androidx.core.view.ViewCompat
 | 
			
		||||
@@ -63,6 +65,10 @@ class SetupFragment : Fragment() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
 | 
			
		||||
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
 | 
			
		||||
            pushNotificationPermissionLauncher.launch(android.Manifest.permission.POST_NOTIFICATIONS)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mainActivity = requireActivity() as MainActivity
 | 
			
		||||
 | 
			
		||||
        homeViewModel.setNavigationVisibility(false)
 | 
			
		||||
@@ -219,6 +225,11 @@ class SetupFragment : Fragment() {
 | 
			
		||||
        _binding = null
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private val pushNotificationPermissionLauncher =
 | 
			
		||||
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
 | 
			
		||||
            // TODO: Show proper notification request reason and confirmation
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private fun finishSetup() {
 | 
			
		||||
        PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
 | 
			
		||||
            .putBoolean(Settings.PREF_FIRST_APP_LAUNCH, false)
 | 
			
		||||
 
 | 
			
		||||
@@ -29,10 +29,10 @@ class ForegroundService : Service() {
 | 
			
		||||
            PendingIntent.FLAG_IMMUTABLE
 | 
			
		||||
        )
 | 
			
		||||
        val builder =
 | 
			
		||||
            NotificationCompat.Builder(this, getString(R.string.app_notification_channel_id))
 | 
			
		||||
            NotificationCompat.Builder(this, getString(R.string.emulation_notification_channel_id))
 | 
			
		||||
                .setSmallIcon(R.drawable.ic_stat_notification_logo)
 | 
			
		||||
                .setContentTitle(getString(R.string.app_name))
 | 
			
		||||
                .setContentText(getString(R.string.app_notification_running))
 | 
			
		||||
                .setContentText(getString(R.string.emulation_notification_running))
 | 
			
		||||
                .setPriority(NotificationCompat.PRIORITY_LOW)
 | 
			
		||||
                .setOngoing(true)
 | 
			
		||||
                .setVibrate(null)
 | 
			
		||||
 
 | 
			
		||||
@@ -4,10 +4,14 @@
 | 
			
		||||
    <!-- General application strings -->
 | 
			
		||||
    <string name="app_name" translatable="false">yuzu</string>
 | 
			
		||||
    <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>
 | 
			
		||||
    <string name="app_notification_channel_name" translatable="false">yuzu</string>
 | 
			
		||||
    <string name="app_notification_channel_id" translatable="false">yuzu</string>
 | 
			
		||||
    <string name="app_notification_channel_description">yuzu Switch emulator notifications</string>
 | 
			
		||||
    <string name="app_notification_running">yuzu is running</string>
 | 
			
		||||
    <string name="emulation_notification_channel_name">Emulation is Active</string>
 | 
			
		||||
    <string name="emulation_notification_channel_id" translatable="false">emulationIsActive</string>
 | 
			
		||||
    <string name="emulation_notification_channel_description">Shows a persistent notification when emulation is running.</string>
 | 
			
		||||
    <string name="emulation_notification_running">yuzu is running</string>
 | 
			
		||||
    <string name="notice_notification_channel_name">Notices and errors</string>
 | 
			
		||||
    <string name="notice_notification_channel_id" translatable="false">noticesAndErrors</string>
 | 
			
		||||
    <string name="notice_notification_channel_description">Shows notifications when something goes wrong.</string>
 | 
			
		||||
    <string name="notification_permission_not_granted">Notification permission not granted!</string>
 | 
			
		||||
 | 
			
		||||
    <!-- Setup strings -->
 | 
			
		||||
    <string name="welcome">Welcome!</string>
 | 
			
		||||
@@ -29,14 +33,14 @@
 | 
			
		||||
    <!-- Home strings -->
 | 
			
		||||
    <string name="home_games">Games</string>
 | 
			
		||||
    <string name="home_settings">Settings</string>
 | 
			
		||||
    <string name="select_games_folder">Select Games Folder</string>
 | 
			
		||||
    <string name="select_games_folder">Select games folder</string>
 | 
			
		||||
    <string name="select_games_folder_description">Allows yuzu to populate the games list</string>
 | 
			
		||||
    <string name="add_games_warning">Skip selecting games folder?</string>
 | 
			
		||||
    <string name="add_games_warning_description">Games won\'t be displayed in the Games list if a folder isn\'t selected.</string>
 | 
			
		||||
    <string name="add_games_warning_help">https://yuzu-emu.org/help/quickstart/#dumping-games</string>
 | 
			
		||||
    <string name="home_search_games">Search Games</string>
 | 
			
		||||
    <string name="games_dir_selected">Games directory selected</string>
 | 
			
		||||
    <string name="install_prod_keys">Install Prod.keys</string>
 | 
			
		||||
    <string name="install_prod_keys">Install prod.keys</string>
 | 
			
		||||
    <string name="install_prod_keys_description">Required to decrypt retail games</string>
 | 
			
		||||
    <string name="install_prod_keys_warning">Skip adding keys?</string>
 | 
			
		||||
    <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 @@
 | 
			
		||||
    <string name="warning_help">Help</string>
 | 
			
		||||
    <string name="warning_skip">Skip</string>
 | 
			
		||||
    <string name="warning_cancel">Cancel</string>
 | 
			
		||||
    <string name="install_amiibo_keys">Install Amiibo Keys</string>
 | 
			
		||||
    <string name="install_amiibo_keys">Install Amiibo keys</string>
 | 
			
		||||
    <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="install_gpu_driver">Install GPU Driver</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>
 | 
			
		||||
    <string name="advanced_settings">Advanced settings</string>
 | 
			
		||||
    <string name="settings_description">Configure emulator settings</string>
 | 
			
		||||
    <string name="open_user_folder">Open yuzu folder</string>
 | 
			
		||||
    <string name="open_user_folder_description">Manage yuzu\'s internal files</string>
 | 
			
		||||
    <string name="no_file_manager">No file manager found</string>
 | 
			
		||||
    <string name="notification_no_directory_link">Couldn\'t open yuzu directory</string>
 | 
			
		||||
    <string name="notification_no_directory_link_description">Please locate the user folder with the file manager\'s side panel manually.</string>
 | 
			
		||||
 | 
			
		||||
    <!-- General settings strings -->
 | 
			
		||||
    <string name="frame_limit_enable">Enable limit speed</string>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user