summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/android/app/build.gradle.kts30
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt26
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/YuzuApplication.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt11
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard.kt29
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/DocumentProvider.kt89
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt6
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt26
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt9
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EarlyAccessFragment.kt10
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt91
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/HomeSettingsFragment.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/ImportExportSavesFragment.kt27
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt1
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SetupFragment.kt23
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt45
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt5
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt28
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt8
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt40
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ControllerMappingHelper.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ForegroundService.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt2
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.kt4
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt19
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InsetsHelper.kt12
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt21
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/SerializableHelper.kt20
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt14
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt4
-rw-r--r--src/android/app/src/main/res/values/strings.xml2
55 files changed, 497 insertions, 289 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts
index a637db78a..7ae538cf9 100644
--- a/src/android/app/build.gradle.kts
+++ b/src/android/app/build.gradle.kts
@@ -2,7 +2,9 @@
2// SPDX-License-Identifier: GPL-3.0-or-later 2// SPDX-License-Identifier: GPL-3.0-or-later
3 3
4import android.annotation.SuppressLint 4import android.annotation.SuppressLint
5import kotlin.collections.setOf
5import org.jetbrains.kotlin.konan.properties.Properties 6import org.jetbrains.kotlin.konan.properties.Properties
7import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
6 8
7plugins { 9plugins {
8 id("com.android.application") 10 id("com.android.application")
@@ -10,6 +12,7 @@ plugins {
10 id("kotlin-parcelize") 12 id("kotlin-parcelize")
11 kotlin("plugin.serialization") version "1.8.21" 13 kotlin("plugin.serialization") version "1.8.21"
12 id("androidx.navigation.safeargs.kotlin") 14 id("androidx.navigation.safeargs.kotlin")
15 id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
13} 16}
14 17
15/** 18/**
@@ -44,16 +47,6 @@ android {
44 jniLibs.useLegacyPackaging = true 47 jniLibs.useLegacyPackaging = true
45 } 48 }
46 49
47 lint {
48 // This is important as it will run lint but not abort on error
49 // Lint has some overly obnoxious "errors" that should really be warnings
50 abortOnError = false
51
52 //Uncomment disable lines for test builds...
53 //disable 'MissingTranslation'bin
54 //disable 'ExtraTranslation'
55 }
56
57 defaultConfig { 50 defaultConfig {
58 // TODO If this is ever modified, change application_id in strings.xml 51 // TODO If this is ever modified, change application_id in strings.xml
59 applicationId = "org.yuzu.yuzu_emu" 52 applicationId = "org.yuzu.yuzu_emu"
@@ -167,6 +160,23 @@ android {
167 } 160 }
168} 161}
169 162
163tasks.getByPath("preBuild").dependsOn("ktlintCheck")
164
165ktlint {
166 version.set("0.47.0")
167 android.set(true)
168 ignoreFailures.set(false)
169 disabledRules.set(
170 setOf(
171 "no-wildcard-imports",
172 "package-name"
173 )
174 )
175 reporters {
176 reporter(ReporterType.CHECKSTYLE)
177 }
178}
179
170dependencies { 180dependencies {
171 implementation("androidx.core:core-ktx:1.10.1") 181 implementation("androidx.core:core-ktx:1.10.1")
172 implementation("androidx.appcompat:appcompat:1.6.1") 182 implementation("androidx.appcompat:appcompat:1.6.1")
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index f3bfbe7eb..f860cdd4b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -14,18 +14,18 @@ import android.widget.TextView
14import androidx.annotation.Keep 14import androidx.annotation.Keep
15import androidx.fragment.app.DialogFragment 15import androidx.fragment.app.DialogFragment
16import com.google.android.material.dialog.MaterialAlertDialogBuilder 16import com.google.android.material.dialog.MaterialAlertDialogBuilder
17import java.lang.ref.WeakReference
17import org.yuzu.yuzu_emu.YuzuApplication.Companion.appContext 18import org.yuzu.yuzu_emu.YuzuApplication.Companion.appContext
18import org.yuzu.yuzu_emu.activities.EmulationActivity 19import org.yuzu.yuzu_emu.activities.EmulationActivity
19import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath 20import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath
20import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize
21import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri
22import org.yuzu.yuzu_emu.utils.FileUtil.exists 21import org.yuzu.yuzu_emu.utils.FileUtil.exists
22import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize
23import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory 23import org.yuzu.yuzu_emu.utils.FileUtil.isDirectory
24import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri
24import org.yuzu.yuzu_emu.utils.Log.error 25import org.yuzu.yuzu_emu.utils.Log.error
25import org.yuzu.yuzu_emu.utils.Log.verbose 26import org.yuzu.yuzu_emu.utils.Log.verbose
26import org.yuzu.yuzu_emu.utils.Log.warning 27import org.yuzu.yuzu_emu.utils.Log.warning
27import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable 28import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
28import java.lang.ref.WeakReference
29 29
30/** 30/**
31 * Class which contains methods that interact 31 * Class which contains methods that interact
@@ -76,7 +76,9 @@ object NativeLibrary {
76 fun openContentUri(path: String?, openmode: String?): Int { 76 fun openContentUri(path: String?, openmode: String?): Int {
77 return if (isNativePath(path!!)) { 77 return if (isNativePath(path!!)) {
78 YuzuApplication.documentsTree!!.openContentUri(path, openmode) 78 YuzuApplication.documentsTree!!.openContentUri(path, openmode)
79 } else openContentUri(appContext, path, openmode) 79 } else {
80 openContentUri(appContext, path, openmode)
81 }
80 } 82 }
81 83
82 @Keep 84 @Keep
@@ -84,7 +86,9 @@ object NativeLibrary {
84 fun getSize(path: String?): Long { 86 fun getSize(path: String?): Long {
85 return if (isNativePath(path!!)) { 87 return if (isNativePath(path!!)) {
86 YuzuApplication.documentsTree!!.getFileSize(path) 88 YuzuApplication.documentsTree!!.getFileSize(path)
87 } else getFileSize(appContext, path) 89 } else {
90 getFileSize(appContext, path)
91 }
88 } 92 }
89 93
90 @Keep 94 @Keep
@@ -92,7 +96,9 @@ object NativeLibrary {
92 fun exists(path: String?): Boolean { 96 fun exists(path: String?): Boolean {
93 return if (isNativePath(path!!)) { 97 return if (isNativePath(path!!)) {
94 YuzuApplication.documentsTree!!.exists(path) 98 YuzuApplication.documentsTree!!.exists(path)
95 } else exists(appContext, path) 99 } else {
100 exists(appContext, path)
101 }
96 } 102 }
97 103
98 @Keep 104 @Keep
@@ -100,7 +106,9 @@ object NativeLibrary {
100 fun isDirectory(path: String?): Boolean { 106 fun isDirectory(path: String?): Boolean {
101 return if (isNativePath(path!!)) { 107 return if (isNativePath(path!!)) {
102 YuzuApplication.documentsTree!!.isDirectory(path) 108 YuzuApplication.documentsTree!!.isDirectory(path)
103 } else isDirectory(appContext, path) 109 } else {
110 isDirectory(appContext, path)
111 }
104 } 112 }
105 113
106 /** 114 /**
@@ -454,7 +462,9 @@ object NativeLibrary {
454 Html.FROM_HTML_MODE_LEGACY 462 Html.FROM_HTML_MODE_LEGACY
455 ) 463 )
456 ) 464 )
457 .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> emulationActivity.finish() } 465 .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
466 emulationActivity.finish()
467 }
458 .setOnDismissListener { emulationActivity.finish() } 468 .setOnDismissListener { emulationActivity.finish() }
459 emulationActivity.runOnUiThread { 469 emulationActivity.runOnUiThread {
460 val alert = builder.create() 470 val alert = builder.create()
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 4c947b786..04ab6a220 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
@@ -7,12 +7,12 @@ import android.app.Application
7import android.app.NotificationChannel 7import android.app.NotificationChannel
8import android.app.NotificationManager 8import android.app.NotificationManager
9import android.content.Context 9import android.content.Context
10import java.io.File
10import org.yuzu.yuzu_emu.utils.DirectoryInitialization 11import org.yuzu.yuzu_emu.utils.DirectoryInitialization
11import org.yuzu.yuzu_emu.utils.DocumentsTree 12import org.yuzu.yuzu_emu.utils.DocumentsTree
12import org.yuzu.yuzu_emu.utils.GpuDriverHelper 13import org.yuzu.yuzu_emu.utils.GpuDriverHelper
13import java.io.File
14 14
15fun Context.getPublicFilesDir() : File = getExternalFilesDir(null) ?: filesDir 15fun Context.getPublicFilesDir(): File = getExternalFilesDir(null) ?: filesDir
16 16
17class YuzuApplication : Application() { 17class YuzuApplication : Application() {
18 private fun createNotificationChannels() { 18 private fun createNotificationChannels() {
@@ -21,7 +21,9 @@ class YuzuApplication : Application() {
21 getString(R.string.emulation_notification_channel_name), 21 getString(R.string.emulation_notification_channel_name),
22 NotificationManager.IMPORTANCE_LOW 22 NotificationManager.IMPORTANCE_LOW
23 ) 23 )
24 emulationChannel.description = getString(R.string.emulation_notification_channel_description) 24 emulationChannel.description = getString(
25 R.string.emulation_notification_channel_description
26 )
25 emulationChannel.setSound(null, null) 27 emulationChannel.setSound(null, null)
26 emulationChannel.vibrationPattern = null 28 emulationChannel.vibrationPattern = null
27 29
@@ -48,7 +50,7 @@ class YuzuApplication : Application() {
48 GpuDriverHelper.initializeDriverParameters(applicationContext) 50 GpuDriverHelper.initializeDriverParameters(applicationContext)
49 NativeLibrary.logDeviceInfo() 51 NativeLibrary.logDeviceInfo()
50 52
51 createNotificationChannels(); 53 createNotificationChannels()
52 } 54 }
53 55
54 companion object { 56 companion object {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 5ca519f0a..f0a6753a9 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -33,6 +33,7 @@ import androidx.core.view.WindowCompat
33import androidx.core.view.WindowInsetsCompat 33import androidx.core.view.WindowInsetsCompat
34import androidx.core.view.WindowInsetsControllerCompat 34import androidx.core.view.WindowInsetsControllerCompat
35import androidx.navigation.fragment.NavHostFragment 35import androidx.navigation.fragment.NavHostFragment
36import kotlin.math.roundToInt
36import org.yuzu.yuzu_emu.NativeLibrary 37import org.yuzu.yuzu_emu.NativeLibrary
37import org.yuzu.yuzu_emu.R 38import org.yuzu.yuzu_emu.R
38import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding 39import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
@@ -45,7 +46,6 @@ import org.yuzu.yuzu_emu.utils.ForegroundService
45import org.yuzu.yuzu_emu.utils.InputHandler 46import org.yuzu.yuzu_emu.utils.InputHandler
46import org.yuzu.yuzu_emu.utils.NfcReader 47import org.yuzu.yuzu_emu.utils.NfcReader
47import org.yuzu.yuzu_emu.utils.ThemeHelper 48import org.yuzu.yuzu_emu.utils.ThemeHelper
48import kotlin.math.roundToInt
49 49
50class EmulationActivity : AppCompatActivity(), SensorEventListener { 50class EmulationActivity : AppCompatActivity(), SensorEventListener {
51 private lateinit var binding: ActivityEmulationBinding 51 private lateinit var binding: ActivityEmulationBinding
@@ -256,7 +256,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
256 } 256 }
257 } 257 }
258 258
259 private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder(): PictureInPictureParams.Builder { 259 private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder():
260 PictureInPictureParams.Builder {
260 val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.int) { 261 val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.int) {
261 0 -> Rational(16, 9) 262 0 -> Rational(16, 9)
262 1 -> Rational(4, 3) 263 1 -> Rational(4, 3)
@@ -267,7 +268,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
267 return this.apply { aspectRatio?.let { setAspectRatio(it) } } 268 return this.apply { aspectRatio?.let { setAspectRatio(it) } }
268 } 269 }
269 270
270 private fun PictureInPictureParams.Builder.getPictureInPictureActionsBuilder(): PictureInPictureParams.Builder { 271 private fun PictureInPictureParams.Builder.getPictureInPictureActionsBuilder():
272 PictureInPictureParams.Builder {
271 val pictureInPictureActions: MutableList<RemoteAction> = mutableListOf() 273 val pictureInPictureActions: MutableList<RemoteAction> = mutableListOf()
272 val pendingFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE 274 val pendingFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
273 275
@@ -310,7 +312,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
310 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder() 312 val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
311 .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder() 313 .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
312 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { 314 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
313 pictureInPictureParamsBuilder.setAutoEnterEnabled(BooleanSetting.PICTURE_IN_PICTURE.boolean) 315 pictureInPictureParamsBuilder.setAutoEnterEnabled(
316 BooleanSetting.PICTURE_IN_PICTURE.boolean
317 )
314 } 318 }
315 setPictureInPictureParams(pictureInPictureParamsBuilder.build()) 319 setPictureInPictureParams(pictureInPictureParamsBuilder.build())
316 } 320 }
@@ -341,7 +345,7 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
341 } else { 345 } else {
342 try { 346 try {
343 unregisterReceiver(pictureInPictureReceiver) 347 unregisterReceiver(pictureInPictureReceiver)
344 } catch (ignored : Exception) { 348 } catch (ignored: Exception) {
345 } 349 }
346 } 350 }
347 } 351 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
index 83d08841b..e91277d35 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
@@ -28,10 +28,9 @@ import org.yuzu.yuzu_emu.HomeNavigationDirections
28import org.yuzu.yuzu_emu.NativeLibrary 28import org.yuzu.yuzu_emu.NativeLibrary
29import org.yuzu.yuzu_emu.R 29import org.yuzu.yuzu_emu.R
30import org.yuzu.yuzu_emu.YuzuApplication 30import org.yuzu.yuzu_emu.YuzuApplication
31import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder
31import org.yuzu.yuzu_emu.databinding.CardGameBinding 32import org.yuzu.yuzu_emu.databinding.CardGameBinding
32import org.yuzu.yuzu_emu.activities.EmulationActivity
33import org.yuzu.yuzu_emu.model.Game 33import org.yuzu.yuzu_emu.model.Game
34import org.yuzu.yuzu_emu.adapters.GameAdapter.GameViewHolder
35import org.yuzu.yuzu_emu.model.GamesViewModel 34import org.yuzu.yuzu_emu.model.GamesViewModel
36 35
37class GameAdapter(private val activity: AppCompatActivity) : 36class GameAdapter(private val activity: AppCompatActivity) :
@@ -60,7 +59,10 @@ class GameAdapter(private val activity: AppCompatActivity) :
60 override fun onClick(view: View) { 59 override fun onClick(view: View) {
61 val holder = view.tag as GameViewHolder 60 val holder = view.tag as GameViewHolder
62 61
63 val gameExists = DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(holder.game.path))?.exists() == true 62 val gameExists = DocumentFile.fromSingleUri(
63 YuzuApplication.appContext,
64 Uri.parse(holder.game.path)
65 )?.exists() == true
64 if (!gameExists) { 66 if (!gameExists) {
65 Toast.makeText( 67 Toast.makeText(
66 YuzuApplication.appContext, 68 YuzuApplication.appContext,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
index b719dd539..d3df3bc81 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/HomeSettingAdapter.kt
@@ -58,11 +58,12 @@ class HomeSettingAdapter(private val activity: AppCompatActivity, var options: L
58 ) 58 )
59 59
60 when (option.titleId) { 60 when (option.titleId) {
61 R.string.get_early_access -> binding.optionLayout.background = 61 R.string.get_early_access ->
62 ContextCompat.getDrawable( 62 binding.optionLayout.background =
63 binding.optionCard.context, 63 ContextCompat.getDrawable(
64 R.drawable.premium_background 64 binding.optionCard.context,
65 ) 65 R.drawable.premium_background
66 )
66 } 67 }
67 } 68 }
68 } 69 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard.kt
index 82a6712b6..e058067c9 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/applets/keyboard/SoftwareKeyboard.kt
@@ -12,10 +12,10 @@ import android.view.WindowInsets
12import android.view.inputmethod.InputMethodManager 12import android.view.inputmethod.InputMethodManager
13import androidx.annotation.Keep 13import androidx.annotation.Keep
14import androidx.core.view.ViewCompat 14import androidx.core.view.ViewCompat
15import java.io.Serializable
15import org.yuzu.yuzu_emu.NativeLibrary 16import org.yuzu.yuzu_emu.NativeLibrary
16import org.yuzu.yuzu_emu.R 17import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.applets.keyboard.ui.KeyboardDialogFragment 18import org.yuzu.yuzu_emu.applets.keyboard.ui.KeyboardDialogFragment
18import java.io.Serializable
19 19
20@Keep 20@Keep
21object SoftwareKeyboard { 21object SoftwareKeyboard {
@@ -40,19 +40,22 @@ object SoftwareKeyboard {
40 // There isn't a good way to know that the IMM is dismissed, so poll every 500ms to submit inline keyboard result. 40 // There isn't a good way to know that the IMM is dismissed, so poll every 500ms to submit inline keyboard result.
41 val handler = Handler(Looper.myLooper()!!) 41 val handler = Handler(Looper.myLooper()!!)
42 val delayMs = 500 42 val delayMs = 500
43 handler.postDelayed(object : Runnable { 43 handler.postDelayed(
44 override fun run() { 44 object : Runnable {
45 val insets = ViewCompat.getRootWindowInsets(overlayView) 45 override fun run() {
46 val isKeyboardVisible = insets!!.isVisible(WindowInsets.Type.ime()) 46 val insets = ViewCompat.getRootWindowInsets(overlayView)
47 if (isKeyboardVisible) { 47 val isKeyboardVisible = insets!!.isVisible(WindowInsets.Type.ime())
48 handler.postDelayed(this, delayMs.toLong()) 48 if (isKeyboardVisible) {
49 return 49 handler.postDelayed(this, delayMs.toLong())
50 } 50 return
51 }
51 52
52 // No longer visible, submit the result. 53 // No longer visible, submit the result.
53 NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER) 54 NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
54 } 55 }
55 }, delayMs.toLong()) 56 },
57 delayMs.toLong()
58 )
56 } 59 }
57 60
58 @JvmStatic 61 @JvmStatic
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt
index 3b1559c80..a18efef19 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/DiskShaderCacheProgress.kt
@@ -20,7 +20,10 @@ object DiskShaderCacheProgress {
20 emulationActivity.getString(R.string.loading), 20 emulationActivity.getString(R.string.loading),
21 emulationActivity.getString(R.string.preparing_shaders) 21 emulationActivity.getString(R.string.preparing_shaders)
22 ) 22 )
23 fragment.show(emulationActivity.supportFragmentManager, ShaderProgressDialogFragment.TAG) 23 fragment.show(
24 emulationActivity.supportFragmentManager,
25 ShaderProgressDialogFragment.TAG
26 )
24 } 27 }
25 synchronized(finishLock) { finishLock.wait() } 28 synchronized(finishLock) { finishLock.wait() }
26 } 29 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt
index 2c68c9ac3..8a8e0a6e8 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/disk_shader_cache/ui/ShaderProgressDialogFragment.kt
@@ -62,7 +62,9 @@ class ShaderProgressDialogFragment : DialogFragment() {
62 shaderProgressViewModel.message.observe(viewLifecycleOwner) { msg -> 62 shaderProgressViewModel.message.observe(viewLifecycleOwner) { msg ->
63 alertDialog.setMessage(msg) 63 alertDialog.setMessage(msg)
64 } 64 }
65 synchronized(DiskShaderCacheProgress.finishLock) { DiskShaderCacheProgress.finishLock.notifyAll() } 65 synchronized(DiskShaderCacheProgress.finishLock) {
66 DiskShaderCacheProgress.finishLock.notifyAll()
67 }
66 } 68 }
67 69
68 override fun onDestroyView() { 70 override fun onDestroyView() {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/DocumentProvider.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/DocumentProvider.kt
index 4c3a9ca80..f3be156b5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/DocumentProvider.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/DocumentProvider.kt
@@ -13,11 +13,11 @@ import android.os.ParcelFileDescriptor
13import android.provider.DocumentsContract 13import android.provider.DocumentsContract
14import android.provider.DocumentsProvider 14import android.provider.DocumentsProvider
15import android.webkit.MimeTypeMap 15import android.webkit.MimeTypeMap
16import java.io.*
16import org.yuzu.yuzu_emu.BuildConfig 17import org.yuzu.yuzu_emu.BuildConfig
17import org.yuzu.yuzu_emu.R 18import org.yuzu.yuzu_emu.R
18import org.yuzu.yuzu_emu.YuzuApplication 19import org.yuzu.yuzu_emu.YuzuApplication
19import org.yuzu.yuzu_emu.getPublicFilesDir 20import org.yuzu.yuzu_emu.getPublicFilesDir
20import java.io.*
21 21
22class DocumentProvider : DocumentsProvider() { 22class DocumentProvider : DocumentsProvider() {
23 private val baseDirectory: File 23 private val baseDirectory: File
@@ -44,7 +44,7 @@ class DocumentProvider : DocumentsProvider() {
44 DocumentsContract.Document.COLUMN_SIZE 44 DocumentsContract.Document.COLUMN_SIZE
45 ) 45 )
46 46
47 const val AUTHORITY : String = BuildConfig.APPLICATION_ID + ".user" 47 const val AUTHORITY: String = BuildConfig.APPLICATION_ID + ".user"
48 const val ROOT_ID: String = "root" 48 const val ROOT_ID: String = "root"
49 } 49 }
50 50
@@ -58,7 +58,11 @@ class DocumentProvider : DocumentsProvider() {
58 private fun getFile(documentId: String): File { 58 private fun getFile(documentId: String): File {
59 if (documentId.startsWith(ROOT_ID)) { 59 if (documentId.startsWith(ROOT_ID)) {
60 val file = baseDirectory.resolve(documentId.drop(ROOT_ID.length + 1)) 60 val file = baseDirectory.resolve(documentId.drop(ROOT_ID.length + 1))
61 if (!file.exists()) throw FileNotFoundException("${file.absolutePath} ($documentId) not found") 61 if (!file.exists()) {
62 throw FileNotFoundException(
63 "${file.absolutePath} ($documentId) not found"
64 )
65 }
62 return file 66 return file
63 } else { 67 } else {
64 throw FileNotFoundException("'$documentId' is not in any known root") 68 throw FileNotFoundException("'$documentId' is not in any known root")
@@ -80,7 +84,8 @@ class DocumentProvider : DocumentsProvider() {
80 add(DocumentsContract.Root.COLUMN_SUMMARY, null) 84 add(DocumentsContract.Root.COLUMN_SUMMARY, null)
81 add( 85 add(
82 DocumentsContract.Root.COLUMN_FLAGS, 86 DocumentsContract.Root.COLUMN_FLAGS,
83 DocumentsContract.Root.FLAG_SUPPORTS_CREATE or DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD 87 DocumentsContract.Root.FLAG_SUPPORTS_CREATE or
88 DocumentsContract.Root.FLAG_SUPPORTS_IS_CHILD
84 ) 89 )
85 add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name)) 90 add(DocumentsContract.Root.COLUMN_TITLE, context!!.getString(R.string.app_name))
86 add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, getDocumentId(baseDirectory)) 91 add(DocumentsContract.Root.COLUMN_DOCUMENT_ID, getDocumentId(baseDirectory))
@@ -127,11 +132,13 @@ class DocumentProvider : DocumentsProvider() {
127 132
128 try { 133 try {
129 if (DocumentsContract.Document.MIME_TYPE_DIR == mimeType) { 134 if (DocumentsContract.Document.MIME_TYPE_DIR == mimeType) {
130 if (!newFile.mkdir()) 135 if (!newFile.mkdir()) {
131 throw IOException("Failed to create directory") 136 throw IOException("Failed to create directory")
137 }
132 } else { 138 } else {
133 if (!newFile.createNewFile()) 139 if (!newFile.createNewFile()) {
134 throw IOException("Failed to create file") 140 throw IOException("Failed to create file")
141 }
135 } 142 }
136 } catch (e: IOException) { 143 } catch (e: IOException) {
137 throw FileNotFoundException("Couldn't create document '${newFile.path}': ${e.message}") 144 throw FileNotFoundException("Couldn't create document '${newFile.path}': ${e.message}")
@@ -142,8 +149,9 @@ class DocumentProvider : DocumentsProvider() {
142 149
143 override fun deleteDocument(documentId: String?) { 150 override fun deleteDocument(documentId: String?) {
144 val file = getFile(documentId!!) 151 val file = getFile(documentId!!)
145 if (!file.delete()) 152 if (!file.delete()) {
146 throw FileNotFoundException("Couldn't delete document with ID '$documentId'") 153 throw FileNotFoundException("Couldn't delete document with ID '$documentId'")
154 }
147 } 155 }
148 156
149 override fun removeDocument(documentId: String, parentDocumentId: String?) { 157 override fun removeDocument(documentId: String, parentDocumentId: String?) {
@@ -151,38 +159,55 @@ class DocumentProvider : DocumentsProvider() {
151 val file = getFile(documentId) 159 val file = getFile(documentId)
152 160
153 if (parent == file || file.parentFile == null || file.parentFile!! == parent) { 161 if (parent == file || file.parentFile == null || file.parentFile!! == parent) {
154 if (!file.delete()) 162 if (!file.delete()) {
155 throw FileNotFoundException("Couldn't delete document with ID '$documentId'") 163 throw FileNotFoundException("Couldn't delete document with ID '$documentId'")
164 }
156 } else { 165 } else {
157 throw FileNotFoundException("Couldn't delete document with ID '$documentId'") 166 throw FileNotFoundException("Couldn't delete document with ID '$documentId'")
158 } 167 }
159 } 168 }
160 169
161 override fun renameDocument(documentId: String?, displayName: String?): String { 170 override fun renameDocument(documentId: String?, displayName: String?): String {
162 if (displayName == null) 171 if (displayName == null) {
163 throw FileNotFoundException("Couldn't rename document '$documentId' as the new name is null") 172 throw FileNotFoundException(
173 "Couldn't rename document '$documentId' as the new name is null"
174 )
175 }
164 176
165 val sourceFile = getFile(documentId!!) 177 val sourceFile = getFile(documentId!!)
166 val sourceParentFile = sourceFile.parentFile 178 val sourceParentFile = sourceFile.parentFile
167 ?: throw FileNotFoundException("Couldn't rename document '$documentId' as it has no parent") 179 ?: throw FileNotFoundException(
180 "Couldn't rename document '$documentId' as it has no parent"
181 )
168 val destFile = sourceParentFile.resolve(displayName) 182 val destFile = sourceParentFile.resolve(displayName)
169 183
170 try { 184 try {
171 if (!sourceFile.renameTo(destFile)) 185 if (!sourceFile.renameTo(destFile)) {
172 throw FileNotFoundException("Couldn't rename document from '${sourceFile.name}' to '${destFile.name}'") 186 throw FileNotFoundException(
187 "Couldn't rename document from '${sourceFile.name}' to '${destFile.name}'"
188 )
189 }
173 } catch (e: Exception) { 190 } catch (e: Exception) {
174 throw FileNotFoundException("Couldn't rename document from '${sourceFile.name}' to '${destFile.name}': ${e.message}") 191 throw FileNotFoundException(
192 "Couldn't rename document from '${sourceFile.name}' to '${destFile.name}': " +
193 "${e.message}"
194 )
175 } 195 }
176 196
177 return getDocumentId(destFile) 197 return getDocumentId(destFile)
178 } 198 }
179 199
180 private fun copyDocument( 200 private fun copyDocument(
181 sourceDocumentId: String, sourceParentDocumentId: String, 201 sourceDocumentId: String,
202 sourceParentDocumentId: String,
182 targetParentDocumentId: String? 203 targetParentDocumentId: String?
183 ): String { 204 ): String {
184 if (!isChildDocument(sourceParentDocumentId, sourceDocumentId)) 205 if (!isChildDocument(sourceParentDocumentId, sourceDocumentId)) {
185 throw FileNotFoundException("Couldn't copy document '$sourceDocumentId' as its parent is not '$sourceParentDocumentId'") 206 throw FileNotFoundException(
207 "Couldn't copy document '$sourceDocumentId' as its parent is not " +
208 "'$sourceParentDocumentId'"
209 )
210 }
186 211
187 return copyDocument(sourceDocumentId, targetParentDocumentId) 212 return copyDocument(sourceDocumentId, targetParentDocumentId)
188 } 213 }
@@ -193,8 +218,13 @@ class DocumentProvider : DocumentsProvider() {
193 val newFile = parent.resolveWithoutConflict(oldFile.name) 218 val newFile = parent.resolveWithoutConflict(oldFile.name)
194 219
195 try { 220 try {
196 if (!(newFile.createNewFile() && newFile.setWritable(true) && newFile.setReadable(true))) 221 if (!(
222 newFile.createNewFile() && newFile.setWritable(true) &&
223 newFile.setReadable(true)
224 )
225 ) {
197 throw IOException("Couldn't create new file") 226 throw IOException("Couldn't create new file")
227 }
198 228
199 FileInputStream(oldFile).use { inStream -> 229 FileInputStream(oldFile).use { inStream ->
200 FileOutputStream(newFile).use { outStream -> 230 FileOutputStream(newFile).use { outStream ->
@@ -209,12 +239,14 @@ class DocumentProvider : DocumentsProvider() {
209 } 239 }
210 240
211 override fun moveDocument( 241 override fun moveDocument(
212 sourceDocumentId: String, sourceParentDocumentId: String?, 242 sourceDocumentId: String,
243 sourceParentDocumentId: String?,
213 targetParentDocumentId: String? 244 targetParentDocumentId: String?
214 ): String { 245 ): String {
215 try { 246 try {
216 val newDocumentId = copyDocument( 247 val newDocumentId = copyDocument(
217 sourceDocumentId, sourceParentDocumentId!!, 248 sourceDocumentId,
249 sourceParentDocumentId!!,
218 targetParentDocumentId 250 targetParentDocumentId
219 ) 251 )
220 removeDocument(sourceDocumentId, sourceParentDocumentId) 252 removeDocument(sourceDocumentId, sourceParentDocumentId)
@@ -245,24 +277,30 @@ class DocumentProvider : DocumentsProvider() {
245 add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, localDocumentId) 277 add(DocumentsContract.Document.COLUMN_DOCUMENT_ID, localDocumentId)
246 add( 278 add(
247 DocumentsContract.Document.COLUMN_DISPLAY_NAME, 279 DocumentsContract.Document.COLUMN_DISPLAY_NAME,
248 if (localFile == baseDirectory) context!!.getString(R.string.app_name) else localFile.name 280 if (localFile == baseDirectory) {
281 context!!.getString(R.string.app_name)
282 } else {
283 localFile.name
284 }
249 ) 285 )
250 add(DocumentsContract.Document.COLUMN_SIZE, localFile.length()) 286 add(DocumentsContract.Document.COLUMN_SIZE, localFile.length())
251 add(DocumentsContract.Document.COLUMN_MIME_TYPE, getTypeForFile(localFile)) 287 add(DocumentsContract.Document.COLUMN_MIME_TYPE, getTypeForFile(localFile))
252 add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, localFile.lastModified()) 288 add(DocumentsContract.Document.COLUMN_LAST_MODIFIED, localFile.lastModified())
253 add(DocumentsContract.Document.COLUMN_FLAGS, flags) 289 add(DocumentsContract.Document.COLUMN_FLAGS, flags)
254 if (localFile == baseDirectory) 290 if (localFile == baseDirectory) {
255 add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_yuzu) 291 add(DocumentsContract.Root.COLUMN_ICON, R.drawable.ic_yuzu)
292 }
256 } 293 }
257 294
258 return cursor 295 return cursor
259 } 296 }
260 297
261 private fun getTypeForFile(file: File): Any { 298 private fun getTypeForFile(file: File): Any {
262 return if (file.isDirectory) 299 return if (file.isDirectory) {
263 DocumentsContract.Document.MIME_TYPE_DIR 300 DocumentsContract.Document.MIME_TYPE_DIR
264 else 301 } else {
265 getTypeForName(file.name) 302 getTypeForName(file.name)
303 }
266 } 304 }
267 305
268 private fun getTypeForName(name: String): Any { 306 private fun getTypeForName(name: String): Any {
@@ -270,8 +308,9 @@ class DocumentProvider : DocumentsProvider() {
270 if (lastDot >= 0) { 308 if (lastDot >= 0) {
271 val extension = name.substring(lastDot + 1) 309 val extension = name.substring(lastDot + 1)
272 val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) 310 val mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension)
273 if (mime != null) 311 if (mime != null) {
274 return mime 312 return mime
313 }
275 } 314 }
276 return "application/octect-stream" 315 return "application/octect-stream"
277 } 316 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index 6bcb7bee0..88afb2223 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -4,11 +4,11 @@
4package org.yuzu.yuzu_emu.features.settings.model 4package org.yuzu.yuzu_emu.features.settings.model
5 5
6import android.text.TextUtils 6import android.text.TextUtils
7import java.util.*
7import org.yuzu.yuzu_emu.R 8import org.yuzu.yuzu_emu.R
8import org.yuzu.yuzu_emu.YuzuApplication 9import org.yuzu.yuzu_emu.YuzuApplication
9import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView 10import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView
10import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 11import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
11import java.util.*
12 12
13class Settings { 13class Settings {
14 private var gameId: String? = null 14 private var gameId: String? = null
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
index 9eac9904e..7306ec458 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt
@@ -4,7 +4,6 @@
4package org.yuzu.yuzu_emu.features.settings.model.view 4package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting 6import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
7import org.yuzu.yuzu_emu.features.settings.model.IntSetting
8 7
9class SingleChoiceSetting( 8class SingleChoiceSetting(
10 setting: AbstractIntSetting?, 9 setting: AbstractIntSetting?,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
index 842648ce4..92d0167ae 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt
@@ -3,13 +3,11 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.model.view 4package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import kotlin.math.roundToInt
6import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting 7import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting
7import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting 8import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting
8import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting 9import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
9import org.yuzu.yuzu_emu.features.settings.model.FloatSetting
10import org.yuzu.yuzu_emu.features.settings.model.IntSetting
11import org.yuzu.yuzu_emu.utils.Log 10import org.yuzu.yuzu_emu.utils.Log
12import kotlin.math.roundToInt
13 11
14class SliderSetting( 12class SliderSetting(
15 setting: AbstractSetting?, 13 setting: AbstractSetting?,
@@ -19,7 +17,7 @@ class SliderSetting(
19 val max: Int, 17 val max: Int,
20 val units: String, 18 val units: String,
21 val key: String? = null, 19 val key: String? = null,
22 val defaultValue: Int? = null, 20 val defaultValue: Int? = null
23) : SettingsItem(setting, titleId, descriptionId) { 21) : SettingsItem(setting, titleId, descriptionId) {
24 override val type = TYPE_SLIDER 22 override val type = TYPE_SLIDER
25 23
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
index 9e9b00d10..bad34fd88 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt
@@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting 6import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
7import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting 7import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting
8import org.yuzu.yuzu_emu.features.settings.model.StringSetting
9 8
10class StringSingleChoiceSetting( 9class StringSingleChoiceSetting(
11 val key: String? = null, 10 val key: String? = null,
@@ -22,7 +21,9 @@ class StringSingleChoiceSetting(
22 if (valuesId == null) return null 21 if (valuesId == null) return null
23 return if (index >= 0 && index < valuesId.size) { 22 return if (index >= 0 && index < valuesId.size) {
24 valuesId[index] 23 valuesId[index]
25 } else "" 24 } else {
25 ""
26 }
26 } 27 }
27 28
28 val selectedValue: String 29 val selectedValue: String
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
index a3ef59c2f..8a9d13a92 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SubmenuSetting.kt
@@ -3,8 +3,6 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.model.view 4package org.yuzu.yuzu_emu.features.settings.model.view
5 5
6import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting
7
8class SubmenuSetting( 6class SubmenuSetting(
9 titleId: Int, 7 titleId: Int,
10 descriptionId: Int, 8 descriptionId: Int,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
index da7062b87..a5af5a7ae 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
@@ -8,18 +8,18 @@ import android.content.Intent
8import android.os.Bundle 8import android.os.Bundle
9import android.view.Menu 9import android.view.Menu
10import android.view.View 10import android.view.View
11import android.view.ViewGroup.MarginLayoutParams
11import android.widget.Toast 12import android.widget.Toast
13import androidx.activity.OnBackPressedCallback
14import androidx.activity.result.ActivityResultLauncher
12import androidx.activity.viewModels 15import androidx.activity.viewModels
13import androidx.appcompat.app.AppCompatActivity 16import androidx.appcompat.app.AppCompatActivity
14import androidx.core.view.ViewCompat 17import androidx.core.view.ViewCompat
15import androidx.core.view.WindowCompat 18import androidx.core.view.WindowCompat
16import androidx.core.view.WindowInsetsCompat 19import androidx.core.view.WindowInsetsCompat
17import android.view.ViewGroup.MarginLayoutParams
18import androidx.activity.OnBackPressedCallback
19import androidx.activity.result.ActivityResultLauncher
20import androidx.core.view.updatePadding 20import androidx.core.view.updatePadding
21import com.google.android.material.color.MaterialColors 21import com.google.android.material.color.MaterialColors
22import org.yuzu.yuzu_emu.NativeLibrary 22import java.io.IOException
23import org.yuzu.yuzu_emu.R 23import org.yuzu.yuzu_emu.R
24import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding 24import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding
25import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting 25import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
@@ -30,7 +30,6 @@ import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
30import org.yuzu.yuzu_emu.features.settings.model.StringSetting 30import org.yuzu.yuzu_emu.features.settings.model.StringSetting
31import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 31import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
32import org.yuzu.yuzu_emu.utils.* 32import org.yuzu.yuzu_emu.utils.*
33import java.io.IOException
34 33
35class SettingsActivity : AppCompatActivity(), SettingsActivityView { 34class SettingsActivity : AppCompatActivity(), SettingsActivityView {
36 private val presenter = SettingsActivityPresenter(this) 35 private val presenter = SettingsActivityPresenter(this)
@@ -60,7 +59,9 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
60 setSupportActionBar(binding.toolbarSettings) 59 setSupportActionBar(binding.toolbarSettings)
61 supportActionBar!!.setDisplayHomeAsUpEnabled(true) 60 supportActionBar!!.setDisplayHomeAsUpEnabled(true)
62 61
63 if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) { 62 if (InsetsHelper.getSystemGestureType(applicationContext) !=
63 InsetsHelper.GESTURE_NAVIGATION
64 ) {
64 binding.navigationBarShade.setBackgroundColor( 65 binding.navigationBarShade.setBackgroundColor(
65 ThemeHelper.getColorWithOpacity( 66 ThemeHelper.getColorWithOpacity(
66 MaterialColors.getColor( 67 MaterialColors.getColor(
@@ -76,7 +77,8 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
76 this, 77 this,
77 object : OnBackPressedCallback(true) { 78 object : OnBackPressedCallback(true) {
78 override fun handleOnBackPressed() = navigateBack() 79 override fun handleOnBackPressed() = navigateBack()
79 }) 80 }
81 )
80 82
81 setInsets() 83 setInsets()
82 } 84 }
@@ -149,11 +151,13 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
149 private fun areSystemAnimationsEnabled(): Boolean { 151 private fun areSystemAnimationsEnabled(): Boolean {
150 val duration = android.provider.Settings.Global.getFloat( 152 val duration = android.provider.Settings.Global.getFloat(
151 contentResolver, 153 contentResolver,
152 android.provider.Settings.Global.ANIMATOR_DURATION_SCALE, 1f 154 android.provider.Settings.Global.ANIMATOR_DURATION_SCALE,
155 1f
153 ) 156 )
154 val transition = android.provider.Settings.Global.getFloat( 157 val transition = android.provider.Settings.Global.getFloat(
155 contentResolver, 158 contentResolver,
156 android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE, 1f 159 android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE,
160 1f
157 ) 161 )
158 return duration != 0f && transition != 0f 162 return duration != 0f && transition != 0f
159 } 163 }
@@ -208,7 +212,9 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
208 get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment? 212 get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment?
209 213
210 private fun setInsets() { 214 private fun setInsets() {
211 ViewCompat.setOnApplyWindowInsetsListener(binding.frameContent) { view: View, windowInsets: WindowInsetsCompat -> 215 ViewCompat.setOnApplyWindowInsetsListener(
216 binding.frameContent
217 ) { view: View, windowInsets: WindowInsetsCompat ->
212 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 218 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
213 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 219 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
214 view.updatePadding( 220 view.updatePadding(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt
index 4361d95fb..93e677b21 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt
@@ -6,12 +6,12 @@ package org.yuzu.yuzu_emu.features.settings.ui
6import android.content.Context 6import android.content.Context
7import android.os.Bundle 7import android.os.Bundle
8import android.text.TextUtils 8import android.text.TextUtils
9import java.io.File
9import org.yuzu.yuzu_emu.NativeLibrary 10import org.yuzu.yuzu_emu.NativeLibrary
10import org.yuzu.yuzu_emu.features.settings.model.Settings 11import org.yuzu.yuzu_emu.features.settings.model.Settings
11import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile 12import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
12import org.yuzu.yuzu_emu.utils.DirectoryInitialization 13import org.yuzu.yuzu_emu.utils.DirectoryInitialization
13import org.yuzu.yuzu_emu.utils.Log 14import org.yuzu.yuzu_emu.utils.Log
14import java.io.File
15 15
16class SettingsActivityPresenter(private val activityView: SettingsActivityView) { 16class SettingsActivityPresenter(private val activityView: SettingsActivityView) {
17 val settings: Settings get() = activityView.settings 17 val settings: Settings get() = activityView.settings
@@ -46,9 +46,15 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
46 46
47 private fun prepareDirectoriesIfNeeded() { 47 private fun prepareDirectoriesIfNeeded() {
48 val configFile = 48 val configFile =
49 File(DirectoryInitialization.userDirectory + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini") 49 File(
50 "${DirectoryInitialization.userDirectory}/config/" +
51 "${SettingsFile.FILE_NAME_CONFIG}.ini"
52 )
50 if (!configFile.exists()) { 53 if (!configFile.exists()) {
51 Log.error(DirectoryInitialization.userDirectory + "/config/" + SettingsFile.FILE_NAME_CONFIG + ".ini") 54 Log.error(
55 "${DirectoryInitialization.userDirectory}/config/" +
56 "${SettingsFile.FILE_NAME_CONFIG}.ini"
57 )
52 Log.error("yuzu config file could not be found!") 58 Log.error("yuzu config file could not be found!")
53 } 59 }
54 60
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
index 1eb4899fc..eac6a134b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -13,7 +13,6 @@ import android.view.ViewGroup
13import android.widget.TextView 13import android.widget.TextView
14import androidx.appcompat.app.AlertDialog 14import androidx.appcompat.app.AlertDialog
15import androidx.appcompat.app.AppCompatActivity 15import androidx.appcompat.app.AppCompatActivity
16import androidx.fragment.app.setFragmentResultListener
17import androidx.recyclerview.widget.RecyclerView 16import androidx.recyclerview.widget.RecyclerView
18import com.google.android.material.datepicker.MaterialDatePicker 17import com.google.android.material.datepicker.MaterialDatePicker
19import com.google.android.material.dialog.MaterialAlertDialogBuilder 18import com.google.android.material.dialog.MaterialAlertDialogBuilder
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
index 867147950..70a74c4dd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt
@@ -50,7 +50,10 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
50 50
51 override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 51 override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
52 settingsAdapter = SettingsAdapter(this, requireActivity()) 52 settingsAdapter = SettingsAdapter(this, requireActivity())
53 val dividerDecoration = MaterialDividerItemDecoration(requireContext(), LinearLayoutManager.VERTICAL) 53 val dividerDecoration = MaterialDividerItemDecoration(
54 requireContext(),
55 LinearLayoutManager.VERTICAL
56 )
54 dividerDecoration.isLastItemDecorated = false 57 dividerDecoration.isLastItemDecorated = false
55 binding.listSettings.apply { 58 binding.listSettings.apply {
56 adapter = settingsAdapter 59 adapter = settingsAdapter
@@ -99,7 +102,9 @@ class SettingsFragment : Fragment(), SettingsFragmentView {
99 } 102 }
100 103
101 private fun setInsets() { 104 private fun setInsets() {
102 ViewCompat.setOnApplyWindowInsetsListener(binding.listSettings) { view: View, windowInsets: WindowInsetsCompat -> 105 ViewCompat.setOnApplyWindowInsetsListener(
106 binding.listSettings
107 ) { view: View, windowInsets: WindowInsetsCompat ->
103 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 108 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
104 view.updatePadding(bottom = insets.bottom) 109 view.updatePadding(bottom = insets.bottom)
105 windowInsets 110 windowInsets
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index b611389a1..c8c85dd7a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -7,7 +7,6 @@ import android.content.SharedPreferences
7import android.os.Build 7import android.os.Build
8import android.text.TextUtils 8import android.text.TextUtils
9import androidx.preference.PreferenceManager 9import androidx.preference.PreferenceManager
10import com.google.android.material.dialog.MaterialAlertDialogBuilder
11import org.yuzu.yuzu_emu.R 10import org.yuzu.yuzu_emu.R
12import org.yuzu.yuzu_emu.YuzuApplication 11import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting 12import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting
@@ -236,7 +235,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
236 private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) { 235 private fun addGraphicsSettings(sl: ArrayList<SettingsItem>) {
237 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics)) 236 settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_graphics))
238 sl.apply { 237 sl.apply {
239
240 add( 238 add(
241 SingleChoiceSetting( 239 SingleChoiceSetting(
242 IntSetting.RENDERER_ACCURACY, 240 IntSetting.RENDERER_ACCURACY,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
index 04c045e77..7955532ee 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt
@@ -4,15 +4,15 @@
4package org.yuzu.yuzu_emu.features.settings.ui.viewholder 4package org.yuzu.yuzu_emu.features.settings.ui.viewholder
5 5
6import android.view.View 6import android.view.View
7import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
8import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
11import java.time.Instant 7import java.time.Instant
12import java.time.ZoneId 8import java.time.ZoneId
13import java.time.ZonedDateTime 9import java.time.ZonedDateTime
14import java.time.format.DateTimeFormatter 10import java.time.format.DateTimeFormatter
15import java.time.format.FormatStyle 11import java.time.format.FormatStyle
12import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding
13import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting
14import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
15import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
16 16
17class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) : 17class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsAdapter) :
18 SettingViewHolder(binding.root, adapter) { 18 SettingViewHolder(binding.root, adapter) {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
index b163bd6ca..54f531795 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/SwitchSettingViewHolder.kt
@@ -6,8 +6,8 @@ package org.yuzu.yuzu_emu.features.settings.ui.viewholder
6import android.view.View 6import android.view.View
7import android.widget.CompoundButton 7import android.widget.CompoundButton
8import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding 8import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding
9import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
10import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem 9import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem
10import org.yuzu.yuzu_emu.features.settings.model.view.SwitchSetting
11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter 11import org.yuzu.yuzu_emu.features.settings.ui.SettingsAdapter
12 12
13class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) : 13class SwitchSettingViewHolder(val binding: ListItemSettingSwitchBinding, adapter: SettingsAdapter) :
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
index e29bca11d..20a0636df 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt
@@ -3,6 +3,8 @@
3 3
4package org.yuzu.yuzu_emu.features.settings.utils 4package org.yuzu.yuzu_emu.features.settings.utils
5 5
6import java.io.*
7import java.util.*
6import org.ini4j.Wini 8import org.ini4j.Wini
7import org.yuzu.yuzu_emu.NativeLibrary 9import org.yuzu.yuzu_emu.NativeLibrary
8import org.yuzu.yuzu_emu.R 10import org.yuzu.yuzu_emu.R
@@ -13,8 +15,6 @@ import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView
13import org.yuzu.yuzu_emu.utils.BiMap 15import org.yuzu.yuzu_emu.utils.BiMap
14import org.yuzu.yuzu_emu.utils.DirectoryInitialization 16import org.yuzu.yuzu_emu.utils.DirectoryInitialization
15import org.yuzu.yuzu_emu.utils.Log 17import org.yuzu.yuzu_emu.utils.Log
16import java.io.*
17import java.util.*
18 18
19/** 19/**
20 * Contains static methods for interacting with .ini files in which settings are stored. 20 * Contains static methods for interacting with .ini files in which settings are stored.
@@ -137,9 +137,12 @@ object SettingsFile {
137 for (settingKey in sortedKeySet) { 137 for (settingKey in sortedKeySet) {
138 val setting = settings[settingKey] 138 val setting = settings[settingKey]
139 NativeLibrary.setUserSetting( 139 NativeLibrary.setUserSetting(
140 gameId, mapSectionNameFromIni( 140 gameId,
141 mapSectionNameFromIni(
141 section.name 142 section.name
142 ), setting!!.key, setting.valueAsString 143 ),
144 setting!!.key,
145 setting.valueAsString
143 ) 146 )
144 } 147 }
145 } 148 }
@@ -148,13 +151,17 @@ object SettingsFile {
148 private fun mapSectionNameFromIni(generalSectionName: String): String? { 151 private fun mapSectionNameFromIni(generalSectionName: String): String? {
149 return if (sectionsMap.getForward(generalSectionName) != null) { 152 return if (sectionsMap.getForward(generalSectionName) != null) {
150 sectionsMap.getForward(generalSectionName) 153 sectionsMap.getForward(generalSectionName)
151 } else generalSectionName 154 } else {
155 generalSectionName
156 }
152 } 157 }
153 158
154 private fun mapSectionNameToIni(generalSectionName: String): String { 159 private fun mapSectionNameToIni(generalSectionName: String): String {
155 return if (sectionsMap.getBackward(generalSectionName) != null) { 160 return if (sectionsMap.getBackward(generalSectionName) != null) {
156 sectionsMap.getBackward(generalSectionName).toString() 161 sectionsMap.getBackward(generalSectionName).toString()
157 } else generalSectionName 162 } else {
163 generalSectionName
164 }
158 } 165 }
159 166
160 fun getSettingsFile(fileName: String): File { 167 fun getSettingsFile(fileName: String): File {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
index c92e2755c..2ff827c6b 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/AboutFragment.kt
@@ -66,7 +66,11 @@ class AboutFragment : Fragment() {
66 true 66 true
67 } 67 }
68 68
69 binding.buttonContributors.setOnClickListener { openLink(getString(R.string.contributors_link)) } 69 binding.buttonContributors.setOnClickListener {
70 openLink(
71 getString(R.string.contributors_link)
72 )
73 }
70 binding.buttonLicenses.setOnClickListener { 74 binding.buttonLicenses.setOnClickListener {
71 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true) 75 exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true)
72 binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment) 76 binding.root.findNavController().navigate(R.id.action_aboutFragment_to_licensesFragment)
@@ -101,7 +105,9 @@ class AboutFragment : Fragment() {
101 } 105 }
102 106
103 private fun setInsets() = 107 private fun setInsets() =
104 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> 108 ViewCompat.setOnApplyWindowInsetsListener(
109 binding.root
110 ) { _: View, windowInsets: WindowInsetsCompat ->
105 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 111 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
106 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 112 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
107 113
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EarlyAccessFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EarlyAccessFragment.kt
index d8bbc1ce4..dbc16da4a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EarlyAccessFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EarlyAccessFragment.kt
@@ -49,7 +49,11 @@ class EarlyAccessFragment : Fragment() {
49 parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack() 49 parentFragmentManager.primaryNavigationFragment?.findNavController()?.popBackStack()
50 } 50 }
51 51
52 binding.getEarlyAccessButton.setOnClickListener { openLink(getString(R.string.play_store_link)) } 52 binding.getEarlyAccessButton.setOnClickListener {
53 openLink(
54 getString(R.string.play_store_link)
55 )
56 }
53 57
54 setInsets() 58 setInsets()
55 } 59 }
@@ -60,7 +64,9 @@ class EarlyAccessFragment : Fragment() {
60 } 64 }
61 65
62 private fun setInsets() = 66 private fun setInsets() =
63 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> 67 ViewCompat.setOnApplyWindowInsetsListener(
68 binding.root
69 ) { _: View, windowInsets: WindowInsetsCompat ->
64 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 70 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
65 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 71 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
66 72
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index 4b2305892..42e2e5b75 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -83,7 +83,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
83 } 83 }
84 84
85 onReturnFromSettings = context.activityResultRegistry.register( 85 onReturnFromSettings = context.activityResultRegistry.register(
86 "SettingsResult", ActivityResultContracts.StartActivityForResult() 86 "SettingsResult",
87 ActivityResultContracts.StartActivityForResult()
87 ) { 88 ) {
88 binding.surfaceEmulation.setAspectRatio( 89 binding.surfaceEmulation.setAspectRatio(
89 when (IntSetting.RENDERER_ASPECT_RATIO.int) { 90 when (IntSetting.RENDERER_ASPECT_RATIO.int) {
@@ -191,9 +192,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
191 requireActivity(), 192 requireActivity(),
192 object : OnBackPressedCallback(true) { 193 object : OnBackPressedCallback(true) {
193 override fun handleOnBackPressed() { 194 override fun handleOnBackPressed() {
194 if (binding.drawerLayout.isOpen) binding.drawerLayout.close() else binding.drawerLayout.open() 195 if (binding.drawerLayout.isOpen) {
196 binding.drawerLayout.close()
197 } else {
198 binding.drawerLayout.open()
199 }
195 } 200 }
196 }) 201 }
202 )
197 203
198 viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { 204 viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
199 lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { 205 lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
@@ -312,8 +318,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
312 private fun updateScreenLayout() { 318 private fun updateScreenLayout() {
313 emulationActivity?.let { 319 emulationActivity?.let {
314 it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) { 320 it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
315 Settings.LayoutOption_MobileLandscape -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE 321 Settings.LayoutOption_MobileLandscape ->
316 Settings.LayoutOption_MobilePortrait -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT 322 ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
323 Settings.LayoutOption_MobilePortrait ->
324 ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
317 Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 325 Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
318 else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE 326 else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
319 } 327 }
@@ -321,25 +329,30 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
321 onConfigurationChanged(resources.configuration) 329 onConfigurationChanged(resources.configuration)
322 } 330 }
323 331
324 private fun updateFoldableLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) { 332 private fun updateFoldableLayout(
325 val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let { 333 emulationActivity: EmulationActivity,
326 if (it.isSeparating) { 334 newLayoutInfo: WindowLayoutInfo
327 emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED 335 ) {
328 if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) { 336 val isFolding =
329 // Restrict emulation and overlays to the top of the screen 337 (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let {
330 binding.emulationContainer.layoutParams.height = it.bounds.top 338 if (it.isSeparating) {
331 binding.overlayContainer.layoutParams.height = it.bounds.top 339 emulationActivity.requestedOrientation =
332 // Restrict input and menu drawer to the bottom of the screen 340 ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
333 binding.inputContainer.layoutParams.height = it.bounds.bottom 341 if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
334 binding.inGameMenu.layoutParams.height = it.bounds.bottom 342 // Restrict emulation and overlays to the top of the screen
335 343 binding.emulationContainer.layoutParams.height = it.bounds.top
336 isInFoldableLayout = true 344 binding.overlayContainer.layoutParams.height = it.bounds.top
337 binding.surfaceInputOverlay.orientation = InputOverlay.FOLDABLE 345 // Restrict input and menu drawer to the bottom of the screen
338 refreshInputOverlay() 346 binding.inputContainer.layoutParams.height = it.bounds.bottom
347 binding.inGameMenu.layoutParams.height = it.bounds.bottom
348
349 isInFoldableLayout = true
350 binding.surfaceInputOverlay.orientation = InputOverlay.FOLDABLE
351 refreshInputOverlay()
352 }
339 } 353 }
340 } 354 it.isSeparating
341 it.isSeparating 355 } ?: false
342 } ?: false
343 if (!isFolding) { 356 if (!isFolding) {
344 binding.emulationContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT 357 binding.emulationContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
345 binding.inputContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT 358 binding.inputContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
@@ -516,18 +529,22 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
516 inputScaleSlider.apply { 529 inputScaleSlider.apply {
517 valueTo = 150F 530 valueTo = 150F
518 value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat() 531 value = preferences.getInt(Settings.PREF_CONTROL_SCALE, 50).toFloat()
519 addOnChangeListener(Slider.OnChangeListener { _, value, _ -> 532 addOnChangeListener(
520 inputScaleValue.text = "${value.toInt()}%" 533 Slider.OnChangeListener { _, value, _ ->
521 setControlScale(value.toInt()) 534 inputScaleValue.text = "${value.toInt()}%"
522 }) 535 setControlScale(value.toInt())
536 }
537 )
523 } 538 }
524 inputOpacitySlider.apply { 539 inputOpacitySlider.apply {
525 valueTo = 100F 540 valueTo = 100F
526 value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat() 541 value = preferences.getInt(Settings.PREF_CONTROL_OPACITY, 100).toFloat()
527 addOnChangeListener(Slider.OnChangeListener { _, value, _ -> 542 addOnChangeListener(
528 inputOpacityValue.text = "${value.toInt()}%" 543 Slider.OnChangeListener { _, value, _ ->
529 setControlOpacity(value.toInt()) 544 inputOpacityValue.text = "${value.toInt()}%"
530 }) 545 setControlOpacity(value.toInt())
546 }
547 )
531 } 548 }
532 inputScaleValue.text = "${inputScaleSlider.value.toInt()}%" 549 inputScaleValue.text = "${inputScaleSlider.value.toInt()}%"
533 inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%" 550 inputOpacityValue.text = "${inputOpacitySlider.value.toInt()}%"
@@ -559,7 +576,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
559 } 576 }
560 577
561 private fun setInsets() { 578 private fun setInsets() {
562 ViewCompat.setOnApplyWindowInsetsListener(binding.inGameMenu) { v: View, windowInsets: WindowInsetsCompat -> 579 ViewCompat.setOnApplyWindowInsetsListener(
580 binding.inGameMenu
581 ) { v: View, windowInsets: WindowInsetsCompat ->
563 val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 582 val cutInsets: Insets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
564 var left = 0 583 var left = 0
565 var right = 0 584 var right = 0
@@ -679,8 +698,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
679 state = State.PAUSED 698 state = State.PAUSED
680 } 699 }
681 700
682 State.PAUSED -> Log.warning("[EmulationFragment] Surface cleared while emulation paused.") 701 State.PAUSED -> Log.warning(
683 else -> Log.warning("[EmulationFragment] Surface cleared while emulation stopped.") 702 "[EmulationFragment] Surface cleared while emulation paused."
703 )
704 else -> Log.warning(
705 "[EmulationFragment] Surface cleared while emulation stopped."
706 )
684 } 707 }
685 } 708 }
686 } 709 }
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 536163eb6..6f8adbba5 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
@@ -103,7 +103,9 @@ class HomeSettingsFragment : Fragment() {
103 R.string.select_games_folder, 103 R.string.select_games_folder,
104 R.string.select_games_folder_description, 104 R.string.select_games_folder_description,
105 R.drawable.ic_add 105 R.drawable.ic_add
106 ) { mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }, 106 ) {
107 mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data)
108 },
107 HomeSetting( 109 HomeSetting(
108 R.string.manage_save_data, 110 R.string.manage_save_data,
109 R.string.import_export_saves_description, 111 R.string.import_export_saves_description,
@@ -225,7 +227,11 @@ class HomeSettingsFragment : Fragment() {
225 val intent = Intent(action) 227 val intent = Intent(action)
226 intent.addCategory(Intent.CATEGORY_DEFAULT) 228 intent.addCategory(Intent.CATEGORY_DEFAULT)
227 intent.data = DocumentsContract.buildRootUri(authority, DocumentProvider.ROOT_ID) 229 intent.data = DocumentsContract.buildRootUri(authority, DocumentProvider.ROOT_ID)
228 intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) 230 intent.addFlags(
231 Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION or
232 Intent.FLAG_GRANT_PREFIX_URI_PERMISSION or
233 Intent.FLAG_GRANT_WRITE_URI_PERMISSION
234 )
229 return intent 235 return intent
230 } 236 }
231 237
@@ -307,7 +313,9 @@ class HomeSettingsFragment : Fragment() {
307 } 313 }
308 314
309 private fun setInsets() = 315 private fun setInsets() =
310 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> 316 ViewCompat.setOnApplyWindowInsetsListener(
317 binding.root
318 ) { view: View, windowInsets: WindowInsetsCompat ->
311 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 319 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
312 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 320 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
313 val spacingNavigation = resources.getDimensionPixelSize(R.dimen.spacing_navigation) 321 val spacingNavigation = resources.getDimensionPixelSize(R.dimen.spacing_navigation)
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 36e63bb9e..e1495ee8c 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
@@ -15,6 +15,14 @@ import androidx.appcompat.app.AppCompatActivity
15import androidx.documentfile.provider.DocumentFile 15import androidx.documentfile.provider.DocumentFile
16import androidx.fragment.app.DialogFragment 16import androidx.fragment.app.DialogFragment
17import com.google.android.material.dialog.MaterialAlertDialogBuilder 17import com.google.android.material.dialog.MaterialAlertDialogBuilder
18import java.io.BufferedOutputStream
19import java.io.File
20import java.io.FileOutputStream
21import java.io.FilenameFilter
22import java.time.LocalDateTime
23import java.time.format.DateTimeFormatter
24import java.util.zip.ZipEntry
25import java.util.zip.ZipOutputStream
18import kotlinx.coroutines.CoroutineScope 26import kotlinx.coroutines.CoroutineScope
19import kotlinx.coroutines.Dispatchers 27import kotlinx.coroutines.Dispatchers
20import kotlinx.coroutines.launch 28import kotlinx.coroutines.launch
@@ -24,14 +32,6 @@ import org.yuzu.yuzu_emu.YuzuApplication
24import org.yuzu.yuzu_emu.features.DocumentProvider 32import org.yuzu.yuzu_emu.features.DocumentProvider
25import org.yuzu.yuzu_emu.getPublicFilesDir 33import org.yuzu.yuzu_emu.getPublicFilesDir
26import org.yuzu.yuzu_emu.utils.FileUtil 34import org.yuzu.yuzu_emu.utils.FileUtil
27import java.io.BufferedOutputStream
28import java.io.File
29import java.io.FileOutputStream
30import java.io.FilenameFilter
31import java.time.LocalDateTime
32import java.time.format.DateTimeFormatter
33import java.util.zip.ZipEntry
34import java.util.zip.ZipOutputStream
35 35
36class ImportExportSavesFragment : DialogFragment() { 36class ImportExportSavesFragment : DialogFragment() {
37 private val context = YuzuApplication.appContext 37 private val context = YuzuApplication.appContext
@@ -98,7 +98,7 @@ class ImportExportSavesFragment : DialogFragment() {
98 val outputZipFile = File( 98 val outputZipFile = File(
99 tempFolder, 99 tempFolder,
100 "yuzu saves - ${ 100 "yuzu saves - ${
101 LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")) 101 LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"))
102 }.zip" 102 }.zip"
103 ) 103 )
104 outputZipFile.createNewFile() 104 outputZipFile.createNewFile()
@@ -106,12 +106,14 @@ class ImportExportSavesFragment : DialogFragment() {
106 saveFolder.walkTopDown().forEach { file -> 106 saveFolder.walkTopDown().forEach { file ->
107 val zipFileName = 107 val zipFileName =
108 file.absolutePath.removePrefix(savesFolderRoot).removePrefix("/") 108 file.absolutePath.removePrefix(savesFolderRoot).removePrefix("/")
109 if (zipFileName == "") 109 if (zipFileName == "") {
110 return@forEach 110 return@forEach
111 }
111 val entry = ZipEntry("$zipFileName${(if (file.isDirectory) "/" else "")}") 112 val entry = ZipEntry("$zipFileName${(if (file.isDirectory) "/" else "")}")
112 zos.putNextEntry(entry) 113 zos.putNextEntry(entry)
113 if (file.isFile) 114 if (file.isFile) {
114 file.inputStream().use { fis -> fis.copyTo(zos) } 115 file.inputStream().use { fis -> fis.copyTo(zos) }
116 }
115 } 117 }
116 } 118 }
117 lastZipCreated = outputZipFile 119 lastZipCreated = outputZipFile
@@ -137,7 +139,8 @@ class ImportExportSavesFragment : DialogFragment() {
137 139
138 withContext(Dispatchers.Main) { 140 withContext(Dispatchers.Main) {
139 val file = DocumentFile.fromSingleUri( 141 val file = DocumentFile.fromSingleUri(
140 context, DocumentsContract.buildDocumentUri( 142 context,
143 DocumentsContract.buildDocumentUri(
141 DocumentProvider.AUTHORITY, 144 DocumentProvider.AUTHORITY,
142 "${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}" 145 "${DocumentProvider.ROOT_ID}/temp/${lastZipFile.name}"
143 ) 146 )
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt
index c7880d8cc..739b26f99 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/IndeterminateProgressDialogFragment.kt
@@ -14,7 +14,6 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder
14import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding 14import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding
15import org.yuzu.yuzu_emu.model.TaskViewModel 15import org.yuzu.yuzu_emu.model.TaskViewModel
16 16
17
18class IndeterminateProgressDialogFragment : DialogFragment() { 17class IndeterminateProgressDialogFragment : DialogFragment() {
19 private val taskViewModel: TaskViewModel by activityViewModels() 18 private val taskViewModel: TaskViewModel by activityViewModels()
20 19
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt
index 59141e823..b6e9129f7 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/LicensesFragment.kt
@@ -113,7 +113,9 @@ class LicensesFragment : Fragment() {
113 } 113 }
114 114
115 private fun setInsets() = 115 private fun setInsets() =
116 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> 116 ViewCompat.setOnApplyWindowInsetsListener(
117 binding.root
118 ) { _: View, windowInsets: WindowInsetsCompat ->
117 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 119 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
118 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 120 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
119 121
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
index adbe3696b..dd6c895fd 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/SearchFragment.kt
@@ -20,6 +20,7 @@ import androidx.fragment.app.activityViewModels
20import androidx.preference.PreferenceManager 20import androidx.preference.PreferenceManager
21import info.debatty.java.stringsimilarity.Jaccard 21import info.debatty.java.stringsimilarity.Jaccard
22import info.debatty.java.stringsimilarity.JaroWinkler 22import info.debatty.java.stringsimilarity.JaroWinkler
23import java.util.Locale
23import org.yuzu.yuzu_emu.R 24import org.yuzu.yuzu_emu.R
24import org.yuzu.yuzu_emu.YuzuApplication 25import org.yuzu.yuzu_emu.YuzuApplication
25import org.yuzu.yuzu_emu.adapters.GameAdapter 26import org.yuzu.yuzu_emu.adapters.GameAdapter
@@ -29,8 +30,6 @@ import org.yuzu.yuzu_emu.model.Game
29import org.yuzu.yuzu_emu.model.GamesViewModel 30import org.yuzu.yuzu_emu.model.GamesViewModel
30import org.yuzu.yuzu_emu.model.HomeViewModel 31import org.yuzu.yuzu_emu.model.HomeViewModel
31import org.yuzu.yuzu_emu.utils.FileUtil 32import org.yuzu.yuzu_emu.utils.FileUtil
32import org.yuzu.yuzu_emu.utils.Log
33import java.util.Locale
34 33
35class SearchFragment : Fragment() { 34class SearchFragment : Fragment() {
36 private var _binding: FragmentSearchBinding? = null 35 private var _binding: FragmentSearchBinding? = null
@@ -130,15 +129,15 @@ class SearchFragment : Fragment() {
130 R.id.chip_homebrew -> baseList.filter { it.isHomebrew } 129 R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
131 130
132 R.id.chip_retail -> baseList.filter { 131 R.id.chip_retail -> baseList.filter {
133 FileUtil.hasExtension(it.path, "xci") 132 FileUtil.hasExtension(it.path, "xci") ||
134 || FileUtil.hasExtension(it.path, "nsp") 133 FileUtil.hasExtension(it.path, "nsp")
135 } 134 }
136 135
137 else -> baseList 136 else -> baseList
138 } 137 }
139 138
140 if (binding.searchText.text.toString().isEmpty() 139 if (binding.searchText.text.toString().isEmpty() &&
141 && binding.chipGroup.checkedChipId != View.NO_ID 140 binding.chipGroup.checkedChipId != View.NO_ID
142 ) { 141 ) {
143 gamesViewModel.setSearchedGames(filteredList) 142 gamesViewModel.setSearchedGames(filteredList)
144 return 143 return
@@ -173,14 +172,16 @@ class SearchFragment : Fragment() {
173 private fun focusSearch() { 172 private fun focusSearch() {
174 if (_binding != null) { 173 if (_binding != null) {
175 binding.searchText.requestFocus() 174 binding.searchText.requestFocus()
176 val imm = 175 val imm = requireActivity()
177 requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager? 176 .getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager?
178 imm?.showSoftInput(binding.searchText, InputMethodManager.SHOW_IMPLICIT) 177 imm?.showSoftInput(binding.searchText, InputMethodManager.SHOW_IMPLICIT)
179 } 178 }
180 } 179 }
181 180
182 private fun setInsets() = 181 private fun setInsets() =
183 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> 182 ViewCompat.setOnApplyWindowInsetsListener(
183 binding.root
184 ) { view: View, windowInsets: WindowInsetsCompat ->
184 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 185 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
185 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 186 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
186 val extraListSpacing = resources.getDimensionPixelSize(R.dimen.spacing_med) 187 val extraListSpacing = resources.getDimensionPixelSize(R.dimen.spacing_med)
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 258773380..6c4ddaf6b 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
@@ -25,6 +25,7 @@ import androidx.navigation.findNavController
25import androidx.preference.PreferenceManager 25import androidx.preference.PreferenceManager
26import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback 26import androidx.viewpager2.widget.ViewPager2.OnPageChangeCallback
27import com.google.android.material.transition.MaterialFadeThrough 27import com.google.android.material.transition.MaterialFadeThrough
28import java.io.File
28import org.yuzu.yuzu_emu.R 29import org.yuzu.yuzu_emu.R
29import org.yuzu.yuzu_emu.YuzuApplication 30import org.yuzu.yuzu_emu.YuzuApplication
30import org.yuzu.yuzu_emu.adapters.SetupAdapter 31import org.yuzu.yuzu_emu.adapters.SetupAdapter
@@ -35,7 +36,6 @@ import org.yuzu.yuzu_emu.model.SetupPage
35import org.yuzu.yuzu_emu.ui.main.MainActivity 36import org.yuzu.yuzu_emu.ui.main.MainActivity
36import org.yuzu.yuzu_emu.utils.DirectoryInitialization 37import org.yuzu.yuzu_emu.utils.DirectoryInitialization
37import org.yuzu.yuzu_emu.utils.GameHelper 38import org.yuzu.yuzu_emu.utils.GameHelper
38import java.io.File
39 39
40class SetupFragment : Fragment() { 40class SetupFragment : Fragment() {
41 private var _binding: FragmentSetupBinding? = null 41 private var _binding: FragmentSetupBinding? = null
@@ -82,7 +82,8 @@ class SetupFragment : Fragment() {
82 requireActivity().finish() 82 requireActivity().finish()
83 } 83 }
84 } 84 }
85 }) 85 }
86 )
86 87
87 requireActivity().window.navigationBarColor = 88 requireActivity().window.navigationBarColor =
88 ContextCompat.getColor(requireContext(), android.R.color.transparent) 89 ContextCompat.getColor(requireContext(), android.R.color.transparent)
@@ -148,14 +149,20 @@ class SetupFragment : Fragment() {
148 R.drawable.ic_add, 149 R.drawable.ic_add,
149 true, 150 true,
150 R.string.add_games, 151 R.string.add_games,
151 { mainActivity.getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) }, 152 {
153 mainActivity.getGamesDirectory.launch(
154 Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data
155 )
156 },
152 true, 157 true,
153 R.string.add_games_warning, 158 R.string.add_games_warning,
154 R.string.add_games_warning_description, 159 R.string.add_games_warning_description,
155 R.string.add_games_warning_help, 160 R.string.add_games_warning_help,
156 { 161 {
157 val preferences = 162 val preferences =
158 PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) 163 PreferenceManager.getDefaultSharedPreferences(
164 YuzuApplication.appContext
165 )
159 preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty() 166 preferences.getString(GameHelper.KEY_GAME_PATH, "")!!.isNotEmpty()
160 } 167 }
161 ) 168 )
@@ -260,7 +267,9 @@ class SetupFragment : Fragment() {
260 @RequiresApi(Build.VERSION_CODES.TIRAMISU) 267 @RequiresApi(Build.VERSION_CODES.TIRAMISU)
261 private val permissionLauncher = 268 private val permissionLauncher =
262 registerForActivityResult(ActivityResultContracts.RequestPermission()) { 269 registerForActivityResult(ActivityResultContracts.RequestPermission()) {
263 if (!it && !shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) { 270 if (!it &&
271 !shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)
272 ) {
264 PermissionDeniedDialogFragment().show( 273 PermissionDeniedDialogFragment().show(
265 childFragmentManager, 274 childFragmentManager,
266 PermissionDeniedDialogFragment.TAG 275 PermissionDeniedDialogFragment.TAG
@@ -315,7 +324,9 @@ class SetupFragment : Fragment() {
315 } 324 }
316 325
317 private fun setInsets() = 326 private fun setInsets() =
318 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> 327 ViewCompat.setOnApplyWindowInsetsListener(
328 binding.root
329 ) { view: View, windowInsets: WindowInsetsCompat ->
319 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 330 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
320 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 331 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
321 view.setPadding( 332 view.setPadding(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt
index be5e4c86c..bdd6ea628 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/layout/AutofitGridLayoutManager.kt
@@ -44,7 +44,9 @@ class AutofitGridLayoutManager(
44 override fun onLayoutChildren(recycler: Recycler, state: RecyclerView.State) { 44 override fun onLayoutChildren(recycler: Recycler, state: RecyclerView.State) {
45 val width = width 45 val width = width
46 val height = height 46 val height = height
47 if (columnWidth > 0 && width > 0 && height > 0 && (isColumnWidthChanged || lastWidth != width || lastHeight != height)) { 47 if (columnWidth > 0 && width > 0 && height > 0 &&
48 (isColumnWidthChanged || lastWidth != width || lastHeight != height)
49 ) {
48 val totalSpace: Int = if (orientation == VERTICAL) { 50 val totalSpace: Int = if (orientation == VERTICAL) {
49 width - paddingRight - paddingLeft 51 width - paddingRight - paddingLeft
50 } else { 52 } else {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
index 35d8000c5..6a048e39f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
@@ -4,9 +4,9 @@
4package org.yuzu.yuzu_emu.model 4package org.yuzu.yuzu_emu.model
5 5
6import android.os.Parcelable 6import android.os.Parcelable
7import java.util.HashSet
7import kotlinx.parcelize.Parcelize 8import kotlinx.parcelize.Parcelize
8import kotlinx.serialization.Serializable 9import kotlinx.serialization.Serializable
9import java.util.HashSet
10 10
11@Parcelize 11@Parcelize
12@Serializable 12@Serializable
@@ -23,8 +23,9 @@ class Game(
23 val keyLastPlayedTime get() = "${gameId}_LastPlayed" 23 val keyLastPlayedTime get() = "${gameId}_LastPlayed"
24 24
25 override fun equals(other: Any?): Boolean { 25 override fun equals(other: Any?): Boolean {
26 if (other !is Game) 26 if (other !is Game) {
27 return false 27 return false
28 }
28 29
29 return hashCode() == other.hashCode() 30 return hashCode() == other.hashCode()
30 } 31 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
index d9b301210..1fe42f922 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
@@ -10,6 +10,7 @@ import androidx.lifecycle.MutableLiveData
10import androidx.lifecycle.ViewModel 10import androidx.lifecycle.ViewModel
11import androidx.lifecycle.viewModelScope 11import androidx.lifecycle.viewModelScope
12import androidx.preference.PreferenceManager 12import androidx.preference.PreferenceManager
13import java.util.Locale
13import kotlinx.coroutines.Dispatchers 14import kotlinx.coroutines.Dispatchers
14import kotlinx.coroutines.launch 15import kotlinx.coroutines.launch
15import kotlinx.coroutines.withContext 16import kotlinx.coroutines.withContext
@@ -20,7 +21,6 @@ import kotlinx.serialization.json.Json
20import org.yuzu.yuzu_emu.NativeLibrary 21import org.yuzu.yuzu_emu.NativeLibrary
21import org.yuzu.yuzu_emu.YuzuApplication 22import org.yuzu.yuzu_emu.YuzuApplication
22import org.yuzu.yuzu_emu.utils.GameHelper 23import org.yuzu.yuzu_emu.utils.GameHelper
23import java.util.Locale
24 24
25@OptIn(ExperimentalSerializationApi::class) 25@OptIn(ExperimentalSerializationApi::class)
26class GamesViewModel : ViewModel() { 26class GamesViewModel : ViewModel() {
@@ -99,8 +99,9 @@ class GamesViewModel : ViewModel() {
99 } 99 }
100 100
101 fun reloadGames(directoryChanged: Boolean) { 101 fun reloadGames(directoryChanged: Boolean) {
102 if (isReloading.value == true) 102 if (isReloading.value == true) {
103 return 103 return
104 }
104 _isReloading.postValue(true) 105 _isReloading.postValue(true)
105 106
106 viewModelScope.launch { 107 viewModelScope.launch {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index d12d08e9f..6251ec783 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.overlay
6import android.app.Activity 6import android.app.Activity
7import android.content.Context 7import android.content.Context
8import android.content.SharedPreferences 8import android.content.SharedPreferences
9import android.content.res.Configuration
10import android.graphics.Bitmap 9import android.graphics.Bitmap
11import android.graphics.Canvas 10import android.graphics.Canvas
12import android.graphics.Point 11import android.graphics.Point
@@ -24,6 +23,8 @@ import android.view.WindowInsets
24import androidx.core.content.ContextCompat 23import androidx.core.content.ContextCompat
25import androidx.preference.PreferenceManager 24import androidx.preference.PreferenceManager
26import androidx.window.layout.WindowMetricsCalculator 25import androidx.window.layout.WindowMetricsCalculator
26import kotlin.math.max
27import kotlin.math.min
27import org.yuzu.yuzu_emu.NativeLibrary 28import org.yuzu.yuzu_emu.NativeLibrary
28import org.yuzu.yuzu_emu.NativeLibrary.ButtonType 29import org.yuzu.yuzu_emu.NativeLibrary.ButtonType
29import org.yuzu.yuzu_emu.NativeLibrary.StickType 30import org.yuzu.yuzu_emu.NativeLibrary.StickType
@@ -31,14 +32,13 @@ import org.yuzu.yuzu_emu.R
31import org.yuzu.yuzu_emu.YuzuApplication 32import org.yuzu.yuzu_emu.YuzuApplication
32import org.yuzu.yuzu_emu.features.settings.model.Settings 33import org.yuzu.yuzu_emu.features.settings.model.Settings
33import org.yuzu.yuzu_emu.utils.EmulationMenuSettings 34import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
34import kotlin.math.max
35import kotlin.math.min
36 35
37/** 36/**
38 * Draws the interactive input overlay on top of the 37 * Draws the interactive input overlay on top of the
39 * [SurfaceView] that is rendering emulation. 38 * [SurfaceView] that is rendering emulation.
40 */ 39 */
41class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context, attrs), 40class InputOverlay(context: Context, attrs: AttributeSet?) :
41 SurfaceView(context, attrs),
42 OnTouchListener { 42 OnTouchListener {
43 private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet() 43 private val overlayButtons: MutableSet<InputOverlayDrawableButton> = HashSet()
44 private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet() 44 private val overlayDpads: MutableSet<InputOverlayDrawableDpad> = HashSet()
@@ -95,7 +95,11 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
95 95
96 var shouldUpdateView = false 96 var shouldUpdateView = false
97 val playerIndex = 97 val playerIndex =
98 if (NativeLibrary.isHandheldOnly()) NativeLibrary.ConsoleDevice else NativeLibrary.Player1Device 98 if (NativeLibrary.isHandheldOnly()) {
99 NativeLibrary.ConsoleDevice
100 } else {
101 NativeLibrary.Player1Device
102 }
99 103
100 for (button in overlayButtons) { 104 for (button in overlayButtons) {
101 if (!button.updateStatus(event)) { 105 if (!button.updateStatus(event)) {
@@ -158,8 +162,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
158 shouldUpdateView = true 162 shouldUpdateView = true
159 } 163 }
160 164
161 if (shouldUpdateView) 165 if (shouldUpdateView) {
162 invalidate() 166 invalidate()
167 }
163 168
164 if (!preferences.getBoolean(Settings.PREF_TOUCH_ENABLED, true)) { 169 if (!preferences.getBoolean(Settings.PREF_TOUCH_ENABLED, true)) {
165 return true 170 return true
@@ -243,9 +248,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
243 // If no button is being moved now, remember the currently touched button to move. 248 // If no button is being moved now, remember the currently touched button to move.
244 if (buttonBeingConfigured == null && 249 if (buttonBeingConfigured == null &&
245 button.bounds.contains( 250 button.bounds.contains(
246 fingerPositionX, 251 fingerPositionX,
247 fingerPositionY 252 fingerPositionY
248 ) 253 )
249 ) { 254 ) {
250 buttonBeingConfigured = button 255 buttonBeingConfigured = button
251 buttonBeingConfigured!!.onConfigureTouch(event) 256 buttonBeingConfigured!!.onConfigureTouch(event)
@@ -309,9 +314,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
309 MotionEvent.ACTION_DOWN, 314 MotionEvent.ACTION_DOWN,
310 MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null && 315 MotionEvent.ACTION_POINTER_DOWN -> if (joystickBeingConfigured == null &&
311 joystick.bounds.contains( 316 joystick.bounds.contains(
312 fingerPositionX, 317 fingerPositionX,
313 fingerPositionY 318 fingerPositionY
314 ) 319 )
315 ) { 320 ) {
316 joystickBeingConfigured = joystick 321 joystickBeingConfigured = joystick
317 joystickBeingConfigured!!.onConfigureTouch(event) 322 joystickBeingConfigured!!.onConfigureTouch(event)
@@ -668,7 +673,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
668 R.integer.SWITCH_STICK_L_Y_FOLDABLE 673 R.integer.SWITCH_STICK_L_Y_FOLDABLE
669 ) 674 )
670 675
671 private fun getResourceValue(orientation: String, position: Int) : Float { 676 private fun getResourceValue(orientation: String, position: Int): Float {
672 return when (orientation) { 677 return when (orientation) {
673 PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000 678 PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000
674 FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000 679 FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000
@@ -820,7 +825,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
820 * @param context Context for getting the vector drawable 825 * @param context Context for getting the vector drawable
821 * @param drawableId The ID of the drawable to scale. 826 * @param drawableId The ID of the drawable to scale.
822 * @param scale The scale factor for the bitmap. 827 * @param scale The scale factor for the bitmap.
823 * @return The scaled [Bitmap] 828 * @return The scaled [Bitmap]
824 */ 829 */
825 private fun getBitmap(context: Context, drawableId: Int, scale: Float): Bitmap { 830 private fun getBitmap(context: Context, drawableId: Int, scale: Float): Bitmap {
826 val vectorDrawable = ContextCompat.getDrawable(context, drawableId) as VectorDrawable 831 val vectorDrawable = ContextCompat.getDrawable(context, drawableId) as VectorDrawable
@@ -854,7 +859,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
854 * Gets the safe screen size for drawing the overlay 859 * Gets the safe screen size for drawing the overlay
855 * 860 *
856 * @param context Context for getting the window metrics 861 * @param context Context for getting the window metrics
857 * @return A pair of points, the first being the top left corner of the safe area, 862 * @return A pair of points, the first being the top left corner of the safe area,
858 * the second being the bottom right corner of the safe area 863 * the second being the bottom right corner of the safe area
859 */ 864 */
860 private fun getSafeScreenSize(context: Context): Pair<Point, Point> { 865 private fun getSafeScreenSize(context: Context): Pair<Point, Point> {
@@ -872,10 +877,16 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
872 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 877 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
873 val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout 878 val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
874 if (insets != null) { 879 if (insets != null) {
875 if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2) 880 if (insets.boundingRectTop.bottom != 0 &&
881 insets.boundingRectTop.bottom > maxY / 2
882 ) {
876 maxY = insets.boundingRectTop.bottom.toFloat() 883 maxY = insets.boundingRectTop.bottom.toFloat()
877 if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2) 884 }
885 if (insets.boundingRectRight.left != 0 &&
886 insets.boundingRectRight.left > maxX / 2
887 ) {
878 maxX = insets.boundingRectRight.left.toFloat() 888 maxX = insets.boundingRectRight.left.toFloat()
889 }
879 890
880 minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left 891 minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
881 minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom 892 minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
index 43d664d21..8aef6f5a5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableDpad.kt
@@ -133,7 +133,10 @@ class InputOverlayDrawableDpad(
133 downButtonState = axisY > VIRT_AXIS_DEADZONE 133 downButtonState = axisY > VIRT_AXIS_DEADZONE
134 leftButtonState = axisX < -VIRT_AXIS_DEADZONE 134 leftButtonState = axisX < -VIRT_AXIS_DEADZONE
135 rightButtonState = axisX > VIRT_AXIS_DEADZONE 135 rightButtonState = axisX > VIRT_AXIS_DEADZONE
136 return oldUpState != upButtonState || oldDownState != downButtonState || oldLeftState != leftButtonState || oldRightState != rightButtonState 136 return oldUpState != upButtonState ||
137 oldDownState != downButtonState ||
138 oldLeftState != leftButtonState ||
139 oldRightState != rightButtonState
137 } 140 }
138 return false 141 return false
139 } 142 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
index f1d32192a..fb48f584d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlayDrawableJoystick.kt
@@ -9,12 +9,12 @@ import android.graphics.Canvas
9import android.graphics.Rect 9import android.graphics.Rect
10import android.graphics.drawable.BitmapDrawable 10import android.graphics.drawable.BitmapDrawable
11import android.view.MotionEvent 11import android.view.MotionEvent
12import org.yuzu.yuzu_emu.NativeLibrary
13import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
14import kotlin.math.atan2 12import kotlin.math.atan2
15import kotlin.math.cos 13import kotlin.math.cos
16import kotlin.math.sin 14import kotlin.math.sin
17import kotlin.math.sqrt 15import kotlin.math.sqrt
16import org.yuzu.yuzu_emu.NativeLibrary
17import org.yuzu.yuzu_emu.utils.EmulationMenuSettings
18 18
19/** 19/**
20 * Custom [BitmapDrawable] that is capable 20 * Custom [BitmapDrawable] that is capable
@@ -241,14 +241,22 @@ class InputOverlayDrawableJoystick(
241 private fun setInnerBounds() { 241 private fun setInnerBounds() {
242 var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt() 242 var x = virtBounds.centerX() + (xAxis * (virtBounds.width() / 2)).toInt()
243 var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt() 243 var y = virtBounds.centerY() + (yAxis * (virtBounds.height() / 2)).toInt()
244 if (x > virtBounds.centerX() + virtBounds.width() / 2) x = 244 if (x > virtBounds.centerX() + virtBounds.width() / 2) {
245 virtBounds.centerX() + virtBounds.width() / 2 245 x =
246 if (x < virtBounds.centerX() - virtBounds.width() / 2) x = 246 virtBounds.centerX() + virtBounds.width() / 2
247 virtBounds.centerX() - virtBounds.width() / 2 247 }
248 if (y > virtBounds.centerY() + virtBounds.height() / 2) y = 248 if (x < virtBounds.centerX() - virtBounds.width() / 2) {
249 virtBounds.centerY() + virtBounds.height() / 2 249 x =
250 if (y < virtBounds.centerY() - virtBounds.height() / 2) y = 250 virtBounds.centerX() - virtBounds.width() / 2
251 virtBounds.centerY() - virtBounds.height() / 2 251 }
252 if (y > virtBounds.centerY() + virtBounds.height() / 2) {
253 y =
254 virtBounds.centerY() + virtBounds.height() / 2
255 }
256 if (y < virtBounds.centerY() - virtBounds.height() / 2) {
257 y =
258 virtBounds.centerY() - virtBounds.height() / 2
259 }
252 val width = pressedStateInnerBitmap.bounds.width() / 2 260 val width = pressedStateInnerBitmap.bounds.width() / 2
253 val height = pressedStateInnerBitmap.bounds.height() / 2 261 val height = pressedStateInnerBitmap.bounds.height() / 2
254 defaultStateInnerBitmap.setBounds( 262 defaultStateInnerBitmap.setBounds(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
index 97eef40d2..b0156dca5 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
@@ -99,7 +99,9 @@ class GamesFragment : Fragment() {
99 } 99 }
100 shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData -> 100 shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData ->
101 if (shouldSwapData) { 101 if (shouldSwapData) {
102 (binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value!!) 102 (binding.gridGames.adapter as GameAdapter).submitList(
103 gamesViewModel.games.value!!
104 )
103 gamesViewModel.setShouldSwapData(false) 105 gamesViewModel.setShouldSwapData(false)
104 } 106 }
105 } 107 }
@@ -128,7 +130,9 @@ class GamesFragment : Fragment() {
128 } 130 }
129 131
130 private fun setInsets() = 132 private fun setInsets() =
131 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { view: View, windowInsets: WindowInsetsCompat -> 133 ViewCompat.setOnApplyWindowInsetsListener(
134 binding.root
135 ) { view: View, windowInsets: WindowInsetsCompat ->
132 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 136 val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
133 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout()) 137 val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
134 val extraListSpacing = resources.getDimensionPixelSize(R.dimen.spacing_large) 138 val extraListSpacing = resources.getDimensionPixelSize(R.dimen.spacing_large)
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 041d16f3a..cc1d87f1b 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
@@ -26,6 +26,9 @@ import androidx.preference.PreferenceManager
26import com.google.android.material.color.MaterialColors 26import com.google.android.material.color.MaterialColors
27import com.google.android.material.dialog.MaterialAlertDialogBuilder 27import com.google.android.material.dialog.MaterialAlertDialogBuilder
28import com.google.android.material.navigation.NavigationBarView 28import com.google.android.material.navigation.NavigationBarView
29import java.io.File
30import java.io.FilenameFilter
31import java.io.IOException
29import kotlinx.coroutines.Dispatchers 32import kotlinx.coroutines.Dispatchers
30import kotlinx.coroutines.launch 33import kotlinx.coroutines.launch
31import kotlinx.coroutines.withContext 34import kotlinx.coroutines.withContext
@@ -43,9 +46,6 @@ import org.yuzu.yuzu_emu.fragments.MessageDialogFragment
43import org.yuzu.yuzu_emu.model.GamesViewModel 46import org.yuzu.yuzu_emu.model.GamesViewModel
44import org.yuzu.yuzu_emu.model.HomeViewModel 47import org.yuzu.yuzu_emu.model.HomeViewModel
45import org.yuzu.yuzu_emu.utils.* 48import org.yuzu.yuzu_emu.utils.*
46import java.io.File
47import java.io.FilenameFilter
48import java.io.IOException
49 49
50class MainActivity : AppCompatActivity(), ThemeProvider { 50class MainActivity : AppCompatActivity(), ThemeProvider {
51 private lateinit var binding: ActivityMainBinding 51 private lateinit var binding: ActivityMainBinding
@@ -86,7 +86,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
86 ThemeHelper.SYSTEM_BAR_ALPHA 86 ThemeHelper.SYSTEM_BAR_ALPHA
87 ) 87 )
88 ) 88 )
89 if (InsetsHelper.getSystemGestureType(applicationContext) != InsetsHelper.GESTURE_NAVIGATION) { 89 if (InsetsHelper.getSystemGestureType(applicationContext) !=
90 InsetsHelper.GESTURE_NAVIGATION
91 ) {
90 binding.navigationBarShade.setBackgroundColor( 92 binding.navigationBarShade.setBackgroundColor(
91 ThemeHelper.getColorWithOpacity( 93 ThemeHelper.getColorWithOpacity(
92 MaterialColors.getColor( 94 MaterialColors.getColor(
@@ -172,7 +174,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
172 binding.navigationView.height.toFloat() * 2 174 binding.navigationView.height.toFloat() * 2
173 translationY(0f) 175 translationY(0f)
174 } else { 176 } else {
175 if (ViewCompat.getLayoutDirection(binding.navigationView) == ViewCompat.LAYOUT_DIRECTION_LTR) { 177 if (ViewCompat.getLayoutDirection(binding.navigationView) ==
178 ViewCompat.LAYOUT_DIRECTION_LTR
179 ) {
176 binding.navigationView.translationX = 180 binding.navigationView.translationX =
177 binding.navigationView.width.toFloat() * -2 181 binding.navigationView.width.toFloat() * -2
178 translationX(0f) 182 translationX(0f)
@@ -189,7 +193,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
189 if (smallLayout) { 193 if (smallLayout) {
190 translationY(binding.navigationView.height.toFloat() * 2) 194 translationY(binding.navigationView.height.toFloat() * 2)
191 } else { 195 } else {
192 if (ViewCompat.getLayoutDirection(binding.navigationView) == ViewCompat.LAYOUT_DIRECTION_LTR) { 196 if (ViewCompat.getLayoutDirection(binding.navigationView) ==
197 ViewCompat.LAYOUT_DIRECTION_LTR
198 ) {
193 translationX(binding.navigationView.width.toFloat() * -2) 199 translationX(binding.navigationView.width.toFloat() * -2)
194 } else { 200 } else {
195 translationX(binding.navigationView.width.toFloat() * 2) 201 translationX(binding.navigationView.width.toFloat() * 2)
@@ -234,7 +240,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
234 } 240 }
235 241
236 private fun setInsets() = 242 private fun setInsets() =
237 ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _: View, windowInsets: WindowInsetsCompat -> 243 ViewCompat.setOnApplyWindowInsetsListener(
244 binding.root
245 ) { _: View, windowInsets: WindowInsetsCompat ->
238 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) 246 val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
239 val mlpStatusShade = binding.statusBarShade.layoutParams as MarginLayoutParams 247 val mlpStatusShade = binding.statusBarShade.layoutParams as MarginLayoutParams
240 mlpStatusShade.height = insets.top 248 mlpStatusShade.height = insets.top
@@ -256,8 +264,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
256 264
257 val getGamesDirectory = 265 val getGamesDirectory =
258 registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result -> 266 registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result ->
259 if (result == null) 267 if (result == null) {
260 return@registerForActivityResult 268 return@registerForActivityResult
269 }
261 270
262 contentResolver.takePersistableUriPermission( 271 contentResolver.takePersistableUriPermission(
263 result, 272 result,
@@ -281,8 +290,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
281 290
282 val getProdKey = 291 val getProdKey =
283 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 292 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
284 if (result == null) 293 if (result == null) {
285 return@registerForActivityResult 294 return@registerForActivityResult
295 }
286 296
287 if (!FileUtil.hasExtension(result, "keys")) { 297 if (!FileUtil.hasExtension(result, "keys")) {
288 MessageDialogFragment.newInstance( 298 MessageDialogFragment.newInstance(
@@ -324,8 +334,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
324 334
325 val getFirmware = 335 val getFirmware =
326 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 336 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
327 if (result == null) 337 if (result == null) {
328 return@registerForActivityResult 338 return@registerForActivityResult
339 }
329 340
330 val inputZip = contentResolver.openInputStream(result) 341 val inputZip = contentResolver.openInputStream(result)
331 if (inputZip == null) { 342 if (inputZip == null) {
@@ -376,8 +387,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
376 387
377 val getAmiiboKey = 388 val getAmiiboKey =
378 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 389 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
379 if (result == null) 390 if (result == null) {
380 return@registerForActivityResult 391 return@registerForActivityResult
392 }
381 393
382 if (!FileUtil.hasExtension(result, "bin")) { 394 if (!FileUtil.hasExtension(result, "bin")) {
383 MessageDialogFragment.newInstance( 395 MessageDialogFragment.newInstance(
@@ -418,8 +430,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
418 430
419 val getDriver = 431 val getDriver =
420 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> 432 registerForActivityResult(ActivityResultContracts.OpenDocument()) { result ->
421 if (result == null) 433 if (result == null) {
422 return@registerForActivityResult 434 return@registerForActivityResult
435 }
423 436
424 val takeFlags = 437 val takeFlags =
425 Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION 438 Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION
@@ -470,8 +483,9 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
470 483
471 val installGameUpdate = 484 val installGameUpdate =
472 registerForActivityResult(ActivityResultContracts.OpenDocument()) { 485 registerForActivityResult(ActivityResultContracts.OpenDocument()) {
473 if (it == null) 486 if (it == null) {
474 return@registerForActivityResult 487 return@registerForActivityResult
488 }
475 489
476 IndeterminateProgressDialogFragment.newInstance( 490 IndeterminateProgressDialogFragment.newInstance(
477 this@MainActivity, 491 this@MainActivity,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ControllerMappingHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ControllerMappingHelper.kt
index 791cea904..eeefcdf20 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ControllerMappingHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ControllerMappingHelper.kt
@@ -19,7 +19,9 @@ class ControllerMappingHelper {
19 // The two analog triggers generate analog motion events as well as a keycode. 19 // The two analog triggers generate analog motion events as well as a keycode.
20 // We always prefer to use the analog values, so throw away the button press 20 // We always prefer to use the analog values, so throw away the button press
21 keyCode == KeyEvent.KEYCODE_BUTTON_L2 || keyCode == KeyEvent.KEYCODE_BUTTON_R2 21 keyCode == KeyEvent.KEYCODE_BUTTON_L2 || keyCode == KeyEvent.KEYCODE_BUTTON_R2
22 } else false 22 } else {
23 false
24 }
23 } 25 }
24 26
25 /** 27 /**
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
index 36c479e6c..2ee63697e 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DirectoryInitialization.kt
@@ -4,8 +4,8 @@
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6import android.content.Context 6import android.content.Context
7import org.yuzu.yuzu_emu.NativeLibrary
8import java.io.IOException 7import java.io.IOException
8import org.yuzu.yuzu_emu.NativeLibrary
9 9
10object DirectoryInitialization { 10object DirectoryInitialization {
11 private var userPath: String? = null 11 private var userPath: String? = null
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.kt
index f8abae445..cf226ad94 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/DocumentsTree.kt
@@ -5,10 +5,10 @@ package org.yuzu.yuzu_emu.utils
5 5
6import android.net.Uri 6import android.net.Uri
7import androidx.documentfile.provider.DocumentFile 7import androidx.documentfile.provider.DocumentFile
8import org.yuzu.yuzu_emu.YuzuApplication
9import org.yuzu.yuzu_emu.model.MinimalDocumentFile
10import java.io.File 8import java.io.File
11import java.util.* 9import java.util.*
10import org.yuzu.yuzu_emu.YuzuApplication
11import org.yuzu.yuzu_emu.model.MinimalDocumentFile
12 12
13class DocumentsTree { 13class DocumentsTree {
14 private var root: DocumentsNode? = null 14 private var root: DocumentsNode? = null
@@ -29,7 +29,9 @@ class DocumentsTree {
29 val node = resolvePath(filepath) 29 val node = resolvePath(filepath)
30 return if (node == null || node.isDirectory) { 30 return if (node == null || node.isDirectory) {
31 0 31 0
32 } else FileUtil.getFileSize(YuzuApplication.appContext, node.uri.toString()) 32 } else {
33 FileUtil.getFileSize(YuzuApplication.appContext, node.uri.toString())
34 }
33 } 35 }
34 36
35 fun exists(filepath: String): Boolean { 37 fun exists(filepath: String): Boolean {
@@ -111,7 +113,9 @@ class DocumentsTree {
111 fun isNativePath(path: String): Boolean { 113 fun isNativePath(path: String): Boolean {
112 return if (path.isNotEmpty()) { 114 return if (path.isNotEmpty()) {
113 path[0] == '/' 115 path[0] == '/'
114 } else false 116 } else {
117 false
118 }
115 } 119 }
116 } 120 }
117} 121}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
index 492b1ad91..9f3bbe56f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/FileUtil.kt
@@ -9,8 +9,6 @@ import android.net.Uri
9import android.provider.DocumentsContract 9import android.provider.DocumentsContract
10import android.provider.OpenableColumns 10import android.provider.OpenableColumns
11import androidx.documentfile.provider.DocumentFile 11import androidx.documentfile.provider.DocumentFile
12import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.model.MinimalDocumentFile
14import java.io.BufferedInputStream 12import java.io.BufferedInputStream
15import java.io.File 13import java.io.File
16import java.io.FileOutputStream 14import java.io.FileOutputStream
@@ -19,6 +17,8 @@ import java.io.InputStream
19import java.net.URLDecoder 17import java.net.URLDecoder
20import java.util.zip.ZipEntry 18import java.util.zip.ZipEntry
21import java.util.zip.ZipInputStream 19import java.util.zip.ZipInputStream
20import org.yuzu.yuzu_emu.YuzuApplication
21import org.yuzu.yuzu_emu.model.MinimalDocumentFile
22 22
23object FileUtil { 23object FileUtil {
24 const val PATH_TREE = "tree" 24 const val PATH_TREE = "tree"
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 dc9b7c744..086d17606 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
@@ -54,7 +54,7 @@ class ForegroundService : Service() {
54 54
55 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { 55 override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
56 if (intent == null) { 56 if (intent == null) {
57 return START_NOT_STICKY; 57 return START_NOT_STICKY
58 } 58 }
59 if (intent.action == ACTION_STOP) { 59 if (intent.action == ACTION_STOP) {
60 NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION) 60 NotificationManagerCompat.from(this).cancel(EMULATION_RUNNING_NOTIFICATION)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
index 42b207618..ee9f3e570 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
@@ -6,12 +6,12 @@ package org.yuzu.yuzu_emu.utils
6import android.content.SharedPreferences 6import android.content.SharedPreferences
7import android.net.Uri 7import android.net.Uri
8import androidx.preference.PreferenceManager 8import androidx.preference.PreferenceManager
9import java.util.*
9import kotlinx.serialization.encodeToString 10import kotlinx.serialization.encodeToString
10import kotlinx.serialization.json.Json 11import kotlinx.serialization.json.Json
11import org.yuzu.yuzu_emu.NativeLibrary 12import org.yuzu.yuzu_emu.NativeLibrary
12import org.yuzu.yuzu_emu.YuzuApplication 13import org.yuzu.yuzu_emu.YuzuApplication
13import org.yuzu.yuzu_emu.model.Game 14import org.yuzu.yuzu_emu.model.Game
14import java.util.*
15 15
16object GameHelper { 16object GameHelper {
17 const val KEY_GAME_PATH = "game_path" 17 const val KEY_GAME_PATH = "game_path"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
index 528011d7f..dad159481 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverHelper.kt
@@ -5,14 +5,14 @@ package org.yuzu.yuzu_emu.utils
5 5
6import android.content.Context 6import android.content.Context
7import android.net.Uri 7import android.net.Uri
8import org.yuzu.yuzu_emu.NativeLibrary
9import org.yuzu.yuzu_emu.utils.FileUtil.copyUriToInternalStorage
10import java.io.BufferedInputStream 8import java.io.BufferedInputStream
11import java.io.File 9import java.io.File
12import java.io.FileInputStream 10import java.io.FileInputStream
13import java.io.FileOutputStream 11import java.io.FileOutputStream
14import java.io.IOException 12import java.io.IOException
15import java.util.zip.ZipInputStream 13import java.util.zip.ZipInputStream
14import org.yuzu.yuzu_emu.NativeLibrary
15import org.yuzu.yuzu_emu.utils.FileUtil.copyUriToInternalStorage
16 16
17object GpuDriverHelper { 17object GpuDriverHelper {
18 private const val META_JSON_FILENAME = "meta.json" 18 private const val META_JSON_FILENAME = "meta.json"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.kt
index 70bdb4097..a4e64070a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GpuDriverMetadata.kt
@@ -3,12 +3,12 @@
3 3
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6import org.json.JSONException
7import org.json.JSONObject
8import java.io.IOException 6import java.io.IOException
9import java.nio.charset.StandardCharsets 7import java.nio.charset.StandardCharsets
10import java.nio.file.Files 8import java.nio.file.Files
11import java.nio.file.Paths 9import java.nio.file.Paths
10import org.json.JSONException
11import org.json.JSONObject
12 12
13class GpuDriverMetadata(metadataFilePath: String) { 13class GpuDriverMetadata(metadataFilePath: String) {
14 var name: String? = null 14 var name: String? = null
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt
index 24e999b29..e963dfbc1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InputHandler.kt
@@ -5,8 +5,8 @@ package org.yuzu.yuzu_emu.utils
5 5
6import android.view.KeyEvent 6import android.view.KeyEvent
7import android.view.MotionEvent 7import android.view.MotionEvent
8import org.yuzu.yuzu_emu.NativeLibrary
9import kotlin.math.sqrt 8import kotlin.math.sqrt
9import org.yuzu.yuzu_emu.NativeLibrary
10 10
11class InputHandler { 11class InputHandler {
12 fun initialize() { 12 fun initialize() {
@@ -68,7 +68,11 @@ class InputHandler {
68 6 -> NativeLibrary.Player6Device 68 6 -> NativeLibrary.Player6Device
69 7 -> NativeLibrary.Player7Device 69 7 -> NativeLibrary.Player7Device
70 8 -> NativeLibrary.Player8Device 70 8 -> NativeLibrary.Player8Device
71 else -> if (NativeLibrary.isHandheldOnly()) NativeLibrary.ConsoleDevice else NativeLibrary.Player1Device 71 else -> if (NativeLibrary.isHandheldOnly()) {
72 NativeLibrary.ConsoleDevice
73 } else {
74 NativeLibrary.Player1Device
75 }
72 } 76 }
73 } 77 }
74 78
@@ -107,7 +111,11 @@ class InputHandler {
107 } 111 }
108 112
109 private fun getAxisToButton(axis: Float): Int { 113 private fun getAxisToButton(axis: Float): Int {
110 return if (axis > 0.5f) NativeLibrary.ButtonState.PRESSED else NativeLibrary.ButtonState.RELEASED 114 return if (axis > 0.5f) {
115 NativeLibrary.ButtonState.PRESSED
116 } else {
117 NativeLibrary.ButtonState.RELEASED
118 }
111 } 119 }
112 120
113 private fun setAxisDpadState(playerNumber: Int, xAxis: Float, yAxis: Float) { 121 private fun setAxisDpadState(playerNumber: Int, xAxis: Float, yAxis: Float) {
@@ -287,7 +295,6 @@ class InputHandler {
287 } 295 }
288 } 296 }
289 297
290
291 private fun setJoyconAxisInput(event: MotionEvent, axis: Int) { 298 private fun setJoyconAxisInput(event: MotionEvent, axis: Int) {
292 // Joycon support is half dead. Right joystick doesn't work 299 // Joycon support is half dead. Right joystick doesn't work
293 val playerNumber = getPlayerNumber(event.device.controllerNumber) 300 val playerNumber = getPlayerNumber(event.device.controllerNumber)
@@ -355,6 +362,4 @@ class InputHandler {
355 ) 362 )
356 } 363 }
357 } 364 }
358 365}
359
360} \ No newline at end of file
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InsetsHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InsetsHelper.kt
index 19c53c481..595f0d284 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InsetsHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/InsetsHelper.kt
@@ -4,9 +4,7 @@
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6import android.annotation.SuppressLint 6import android.annotation.SuppressLint
7import android.app.Activity
8import android.content.Context 7import android.content.Context
9import android.graphics.Rect
10 8
11object InsetsHelper { 9object InsetsHelper {
12 const val THREE_BUTTON_NAVIGATION = 0 10 const val THREE_BUTTON_NAVIGATION = 0
@@ -20,12 +18,8 @@ object InsetsHelper {
20 resources.getIdentifier("config_navBarInteractionMode", "integer", "android") 18 resources.getIdentifier("config_navBarInteractionMode", "integer", "android")
21 return if (resourceId != 0) { 19 return if (resourceId != 0) {
22 resources.getInteger(resourceId) 20 resources.getInteger(resourceId)
23 } else 0 21 } else {
24 } 22 0
25 23 }
26 fun getBottomPaddingRequired(activity: Activity): Int {
27 val visibleFrame = Rect()
28 activity.window.decorView.getWindowVisibleDisplayFrame(visibleFrame)
29 return visibleFrame.bottom - visibleFrame.top - activity.resources.displayMetrics.heightPixels
30 } 24 }
31} 25}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt
index 344dd8a0a..68ed66565 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NfcReader.kt
@@ -13,8 +13,8 @@ import android.nfc.tech.NfcA
13import android.os.Build 13import android.os.Build
14import android.os.Handler 14import android.os.Handler
15import android.os.Looper 15import android.os.Looper
16import org.yuzu.yuzu_emu.NativeLibrary
17import java.io.IOException 16import java.io.IOException
17import org.yuzu.yuzu_emu.NativeLibrary
18 18
19class NfcReader(private val activity: Activity) { 19class NfcReader(private val activity: Activity) {
20 private var nfcAdapter: NfcAdapter? = null 20 private var nfcAdapter: NfcAdapter? = null
@@ -25,10 +25,13 @@ class NfcReader(private val activity: Activity) {
25 25
26 pendingIntent = PendingIntent.getActivity( 26 pendingIntent = PendingIntent.getActivity(
27 activity, 27 activity,
28 0, Intent(activity, activity.javaClass), 28 0,
29 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) 29 Intent(activity, activity.javaClass),
30 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
30 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE 31 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
31 else PendingIntent.FLAG_UPDATE_CURRENT 32 } else {
33 PendingIntent.FLAG_UPDATE_CURRENT
34 }
32 ) 35 )
33 36
34 val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) 37 val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED)
@@ -45,9 +48,9 @@ class NfcReader(private val activity: Activity) {
45 48
46 fun onNewIntent(intent: Intent) { 49 fun onNewIntent(intent: Intent) {
47 val action = intent.action 50 val action = intent.action
48 if (NfcAdapter.ACTION_TAG_DISCOVERED != action 51 if (NfcAdapter.ACTION_TAG_DISCOVERED != action &&
49 && NfcAdapter.ACTION_TECH_DISCOVERED != action 52 NfcAdapter.ACTION_TECH_DISCOVERED != action &&
50 && NfcAdapter.ACTION_NDEF_DISCOVERED != action 53 NfcAdapter.ACTION_NDEF_DISCOVERED != action
51 ) { 54 ) {
52 return 55 return
53 } 56 }
@@ -84,7 +87,7 @@ class NfcReader(private val activity: Activity) {
84 } 87 }
85 88
86 private fun ntag215ReadAll(amiibo: NfcA): ByteArray? { 89 private fun ntag215ReadAll(amiibo: NfcA): ByteArray? {
87 val bufferSize = amiibo.maxTransceiveLength; 90 val bufferSize = amiibo.maxTransceiveLength
88 val tagSize = 0x21C 91 val tagSize = 0x21C
89 val pageSize = 4 92 val pageSize = 4
90 val lastPage = tagSize / pageSize - 1 93 val lastPage = tagSize / pageSize - 1
@@ -103,7 +106,7 @@ class NfcReader(private val activity: Activity) {
103 val data = ntag215FastRead(amiibo, dataStart, dataEnd - 1) 106 val data = ntag215FastRead(amiibo, dataStart, dataEnd - 1)
104 System.arraycopy(data, 0, tagData, i, (dataEnd - dataStart) * pageSize) 107 System.arraycopy(data, 0, tagData, i, (dataEnd - dataStart) * pageSize)
105 } catch (e: IOException) { 108 } catch (e: IOException) {
106 return null; 109 return null
107 } 110 }
108 } 111 }
109 return tagData 112 return tagData
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/SerializableHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/SerializableHelper.kt
index 87ee7f2e6..00e58faec 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/SerializableHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/SerializableHelper.kt
@@ -11,30 +11,34 @@ import java.io.Serializable
11 11
12object SerializableHelper { 12object SerializableHelper {
13 inline fun <reified T : Serializable> Bundle.serializable(key: String): T? { 13 inline fun <reified T : Serializable> Bundle.serializable(key: String): T? {
14 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 14 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
15 getSerializable(key, T::class.java) 15 getSerializable(key, T::class.java)
16 else 16 } else {
17 getSerializable(key) as? T 17 getSerializable(key) as? T
18 }
18 } 19 }
19 20
20 inline fun <reified T : Serializable> Intent.serializable(key: String): T? { 21 inline fun <reified T : Serializable> Intent.serializable(key: String): T? {
21 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 22 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
22 getSerializableExtra(key, T::class.java) 23 getSerializableExtra(key, T::class.java)
23 else 24 } else {
24 getSerializableExtra(key) as? T 25 getSerializableExtra(key) as? T
26 }
25 } 27 }
26 28
27 inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? { 29 inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? {
28 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 30 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
29 getParcelable(key, T::class.java) 31 getParcelable(key, T::class.java)
30 else 32 } else {
31 getParcelable(key) as? T 33 getParcelable(key) as? T
34 }
32 } 35 }
33 36
34 inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? { 37 inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? {
35 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) 38 return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
36 getParcelableExtra(key, T::class.java) 39 getParcelableExtra(key, T::class.java)
37 else 40 } else {
38 getParcelableExtra(key) as? T 41 getParcelableExtra(key) as? T
42 }
39 } 43 }
40} 44}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt
index e55767c0f..f312e24cf 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/ThemeHelper.kt
@@ -3,21 +3,19 @@
3 3
4package org.yuzu.yuzu_emu.utils 4package org.yuzu.yuzu_emu.utils
5 5
6import android.app.Activity
7import android.content.res.Configuration 6import android.content.res.Configuration
8import android.graphics.Color 7import android.graphics.Color
9import androidx.annotation.ColorInt 8import androidx.annotation.ColorInt
10import androidx.appcompat.app.AppCompatActivity 9import androidx.appcompat.app.AppCompatActivity
11import androidx.appcompat.app.AppCompatDelegate 10import androidx.appcompat.app.AppCompatDelegate
12import androidx.core.content.ContextCompat
13import androidx.core.view.WindowCompat 11import androidx.core.view.WindowCompat
14import androidx.core.view.WindowInsetsControllerCompat 12import androidx.core.view.WindowInsetsControllerCompat
15import androidx.preference.PreferenceManager 13import androidx.preference.PreferenceManager
14import kotlin.math.roundToInt
16import org.yuzu.yuzu_emu.R 15import org.yuzu.yuzu_emu.R
17import org.yuzu.yuzu_emu.YuzuApplication 16import org.yuzu.yuzu_emu.YuzuApplication
18import org.yuzu.yuzu_emu.features.settings.model.Settings 17import org.yuzu.yuzu_emu.features.settings.model.Settings
19import org.yuzu.yuzu_emu.ui.main.ThemeProvider 18import org.yuzu.yuzu_emu.ui.main.ThemeProvider
20import kotlin.math.roundToInt
21 19
22object ThemeHelper { 20object ThemeHelper {
23 const val SYSTEM_BAR_ALPHA = 0.9f 21 const val SYSTEM_BAR_ALPHA = 0.9f
@@ -36,8 +34,8 @@ object ThemeHelper {
36 // Using a specific night mode check because this could apply incorrectly when using the 34 // Using a specific night mode check because this could apply incorrectly when using the
37 // light app mode, dark system mode, and black backgrounds. Launching the settings activity 35 // light app mode, dark system mode, and black backgrounds. Launching the settings activity
38 // will then show light mode colors/navigation bars but with black backgrounds. 36 // will then show light mode colors/navigation bars but with black backgrounds.
39 if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) 37 if (preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) &&
40 && isNightMode(activity) 38 isNightMode(activity)
41 ) { 39 ) {
42 activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark) 40 activity.setTheme(R.style.ThemeOverlay_Yuzu_Dark)
43 } 41 }
@@ -46,8 +44,10 @@ object ThemeHelper {
46 @ColorInt 44 @ColorInt
47 fun getColorWithOpacity(@ColorInt color: Int, alphaFactor: Float): Int { 45 fun getColorWithOpacity(@ColorInt color: Int, alphaFactor: Float): Int {
48 return Color.argb( 46 return Color.argb(
49 (alphaFactor * Color.alpha(color)).roundToInt(), Color.red(color), 47 (alphaFactor * Color.alpha(color)).roundToInt(),
50 Color.green(color), Color.blue(color) 48 Color.red(color),
49 Color.green(color),
50 Color.blue(color)
51 ) 51 )
52 } 52 }
53 53
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt
index d89a89983..685ccaa76 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt
@@ -38,8 +38,8 @@ class FixedRatioSurfaceView @JvmOverloads constructor(
38 newWidth = width 38 newWidth = width
39 newHeight = (width / aspectRatio).roundToInt() 39 newHeight = (width / aspectRatio).roundToInt()
40 } 40 }
41 val left = (width - newWidth) / 2; 41 val left = (width - newWidth) / 2
42 val top = (height - newHeight) / 2; 42 val top = (height - newHeight) / 2
43 setLeftTopRightBottom(left, top, left + newWidth, top + newHeight) 43 setLeftTopRightBottom(left, top, left + newWidth, top + newHeight)
44 } else { 44 } else {
45 setLeftTopRightBottom(0, 0, width, height) 45 setLeftTopRightBottom(0, 0, width, height)
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index b5bc249d4..2f2059d42 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -1,5 +1,5 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<resources> 2<resources xmlns:tools="http://schemas.android.com/tools" tools:ignore="MissingTranslation">
3 3
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>