diff options
author | Charles Lombardo <clombardo169@gmail.com> | 2023-05-01 04:14:57 +0200 |
---|---|---|
committer | bunnei <bunneidev@gmail.com> | 2023-06-03 09:05:57 +0200 |
commit | 912bf6a0c65036ba1d0da03716db77ce26823b82 (patch) | |
tree | fbe358fe583a24d2117ecda7c2912a9f8ebdce81 | |
parent | android: Fix inline keyboard input (diff) | |
download | yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.gz yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.bz2 yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.lz yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.xz yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.tar.zst yuzu-912bf6a0c65036ba1d0da03716db77ce26823b82.zip |
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 @@ <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" 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 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 { 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 @@ 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 @@ -50,6 +58,11 @@ class HomeSettingsFragment : Fragment() { 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, R.drawable.ic_input @@ -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 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 @@ 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) 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() { 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) 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 @@ <!-- 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> |