summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar liamwhite2023-07-02 11:29:08 -0400
committerGravatar GitHub2023-07-02 11:29:08 -0400
commit657ab0287d1e7aa42ac01c49c26768e21b2088f7 (patch)
treea1ad316c11506d78f8f419853a9761630b79a393
parentMerge pull request #10942 from FernandoS27/android-is-a-pain-in-the-a-- (diff)
parentandroid: Show memory warning once (diff)
downloadyuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.tar.gz
yuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.tar.xz
yuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.zip
Merge pull request #10949 from t895/memory-requirements
android: Rework MemoryUtil
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt35
-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/utils/MemoryUtil.kt120
-rw-r--r--src/android/app/src/main/res/values/strings.xml1
4 files changed, 114 insertions, 44 deletions
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 ae665ed2e..7461fb093 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
@@ -34,11 +34,14 @@ import androidx.core.view.WindowCompat
34import androidx.core.view.WindowInsetsCompat 34import androidx.core.view.WindowInsetsCompat
35import androidx.core.view.WindowInsetsControllerCompat 35import androidx.core.view.WindowInsetsControllerCompat
36import androidx.navigation.fragment.NavHostFragment 36import androidx.navigation.fragment.NavHostFragment
37import androidx.preference.PreferenceManager
37import org.yuzu.yuzu_emu.NativeLibrary 38import org.yuzu.yuzu_emu.NativeLibrary
38import org.yuzu.yuzu_emu.R 39import org.yuzu.yuzu_emu.R
40import org.yuzu.yuzu_emu.YuzuApplication
39import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding 41import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
40import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting 42import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
41import org.yuzu.yuzu_emu.features.settings.model.IntSetting 43import org.yuzu.yuzu_emu.features.settings.model.IntSetting
44import org.yuzu.yuzu_emu.features.settings.model.Settings
42import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel 45import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
43import org.yuzu.yuzu_emu.model.Game 46import org.yuzu.yuzu_emu.model.Game
44import org.yuzu.yuzu_emu.utils.ControllerMappingHelper 47import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
@@ -47,6 +50,7 @@ import org.yuzu.yuzu_emu.utils.InputHandler
47import org.yuzu.yuzu_emu.utils.MemoryUtil 50import org.yuzu.yuzu_emu.utils.MemoryUtil
48import org.yuzu.yuzu_emu.utils.NfcReader 51import org.yuzu.yuzu_emu.utils.NfcReader
49import org.yuzu.yuzu_emu.utils.ThemeHelper 52import org.yuzu.yuzu_emu.utils.ThemeHelper
53import java.text.NumberFormat
50import kotlin.math.roundToInt 54import kotlin.math.roundToInt
51 55
52class EmulationActivity : AppCompatActivity(), SensorEventListener { 56class EmulationActivity : AppCompatActivity(), SensorEventListener {
@@ -106,17 +110,26 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
106 inputHandler = InputHandler() 110 inputHandler = InputHandler()
107 inputHandler.initialize() 111 inputHandler.initialize()
108 112
109 val memoryUtil = MemoryUtil(this) 113 val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
110 if (memoryUtil.isLessThan(8, MemoryUtil.Gb)) { 114 if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) {
111 Toast.makeText( 115 if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) {
112 this, 116 Toast.makeText(
113 getString( 117 this,
114 R.string.device_memory_inadequate, 118 getString(
115 memoryUtil.getDeviceRAM(), 119 R.string.device_memory_inadequate,
116 "8 ${getString(R.string.memory_gigabyte)}" 120 MemoryUtil.getDeviceRAM(),
117 ), 121 getString(
118 Toast.LENGTH_LONG 122 R.string.memory_formatted,
119 ).show() 123 NumberFormat.getInstance().format(MemoryUtil.REQUIRED_MEMORY),
124 getString(R.string.memory_gigabyte)
125 )
126 ),
127 Toast.LENGTH_LONG
128 ).show()
129 preferences.edit()
130 .putBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, true)
131 .apply()
132 }
120 } 133 }
121 134
122 // Start a foreground service to prevent the app from getting killed in the background 135 // Start a foreground service to prevent the app from getting killed in the background
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 88afb2223..be6e17e65 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
@@ -110,6 +110,8 @@ class Settings {
110 const val SECTION_THEME = "Theme" 110 const val SECTION_THEME = "Theme"
111 const val SECTION_DEBUG = "Debug" 111 const val SECTION_DEBUG = "Debug"
112 112
113 const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
114
113 const val PREF_OVERLAY_INIT = "OverlayInit" 115 const val PREF_OVERLAY_INIT = "OverlayInit"
114 const val PREF_CONTROL_SCALE = "controlScale" 116 const val PREF_CONTROL_SCALE = "controlScale"
115 const val PREF_CONTROL_OPACITY = "controlOpacity" 117 const val PREF_CONTROL_OPACITY = "controlOpacity"
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt
index 18e5fa0b0..aa4a5539a 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt
@@ -5,35 +5,101 @@ package org.yuzu.yuzu_emu.utils
5 5
6import android.app.ActivityManager 6import android.app.ActivityManager
7import android.content.Context 7import android.content.Context
8import android.os.Build
8import org.yuzu.yuzu_emu.R 9import org.yuzu.yuzu_emu.R
10import org.yuzu.yuzu_emu.YuzuApplication
9import java.util.Locale 11import java.util.Locale
12import kotlin.math.ceil
10 13
11class MemoryUtil(val context: Context) { 14object MemoryUtil {
15 private val context get() = YuzuApplication.appContext
12 16
13 private val Long.floatForm: String 17 private val Float.hundredths: String
14 get() = String.format(Locale.ROOT, "%.2f", this.toDouble()) 18 get() = String.format(Locale.ROOT, "%.2f", this)
15 19
16 private fun bytesToSizeUnit(size: Long): String { 20 // Required total system memory
17 return when { 21 const val REQUIRED_MEMORY = 8
18 size < Kb -> "${size.floatForm} ${context.getString(R.string.memory_byte)}" 22
19 size < Mb -> "${(size / Kb).floatForm} ${context.getString(R.string.memory_kilobyte)}" 23 const val Kb: Float = 1024F
20 size < Gb -> "${(size / Mb).floatForm} ${context.getString(R.string.memory_megabyte)}" 24 const val Mb = Kb * 1024
21 size < Tb -> "${(size / Gb).floatForm} ${context.getString(R.string.memory_gigabyte)}" 25 const val Gb = Mb * 1024
22 size < Pb -> "${(size / Tb).floatForm} ${context.getString(R.string.memory_terabyte)}" 26 const val Tb = Gb * 1024
23 size < Eb -> "${(size / Pb).floatForm} ${context.getString(R.string.memory_petabyte)}" 27 const val Pb = Tb * 1024
24 else -> "${(size / Eb).floatForm} ${context.getString(R.string.memory_exabyte)}" 28 const val Eb = Pb * 1024
29
30 private fun bytesToSizeUnit(size: Float): String =
31 when {
32 size < Kb -> {
33 context.getString(
34 R.string.memory_formatted,
35 size.hundredths,
36 context.getString(R.string.memory_byte)
37 )
38 }
39 size < Mb -> {
40 context.getString(
41 R.string.memory_formatted,
42 (size / Kb).hundredths,
43 context.getString(R.string.memory_kilobyte)
44 )
45 }
46 size < Gb -> {
47 context.getString(
48 R.string.memory_formatted,
49 (size / Mb).hundredths,
50 context.getString(R.string.memory_megabyte)
51 )
52 }
53 size < Tb -> {
54 context.getString(
55 R.string.memory_formatted,
56 (size / Gb).hundredths,
57 context.getString(R.string.memory_gigabyte)
58 )
59 }
60 size < Pb -> {
61 context.getString(
62 R.string.memory_formatted,
63 (size / Tb).hundredths,
64 context.getString(R.string.memory_terabyte)
65 )
66 }
67 size < Eb -> {
68 context.getString(
69 R.string.memory_formatted,
70 (size / Pb).hundredths,
71 context.getString(R.string.memory_petabyte)
72 )
73 }
74 else -> {
75 context.getString(
76 R.string.memory_formatted,
77 (size / Eb).hundredths,
78 context.getString(R.string.memory_exabyte)
79 )
80 }
25 } 81 }
26 }
27 82
28 private val totalMemory = 83 // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
29 with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { 84 // the potential error created by memInfo.totalMem
85 private val totalMemory: Float
86 get() {
30 val memInfo = ActivityManager.MemoryInfo() 87 val memInfo = ActivityManager.MemoryInfo()
31 getMemoryInfo(memInfo) 88 with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
32 memInfo.totalMem 89 getMemoryInfo(memInfo)
90 }
91
92 return ceil(
93 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
94 memInfo.advertisedMem.toFloat()
95 } else {
96 memInfo.totalMem.toFloat()
97 }
98 )
33 } 99 }
34 100
35 fun isLessThan(minimum: Int, size: Long): Boolean { 101 fun isLessThan(minimum: Int, size: Float): Boolean =
36 return when (size) { 102 when (size) {
37 Kb -> totalMemory < Mb && totalMemory < minimum 103 Kb -> totalMemory < Mb && totalMemory < minimum
38 Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum 104 Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
39 Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum 105 Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
@@ -42,18 +108,6 @@ class MemoryUtil(val context: Context) {
42 Eb -> totalMemory / Eb < minimum 108 Eb -> totalMemory / Eb < minimum
43 else -> totalMemory < Kb && totalMemory < minimum 109 else -> totalMemory < Kb && totalMemory < minimum
44 } 110 }
45 } 111
46 112 fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory)
47 fun getDeviceRAM(): String {
48 return bytesToSizeUnit(totalMemory)
49 }
50
51 companion object {
52 const val Kb: Long = 1024
53 const val Mb = Kb * 1024
54 const val Gb = Mb * 1024
55 const val Tb = Gb * 1024
56 const val Pb = Tb * 1024
57 const val Eb = Pb * 1024
58 }
59} 113}
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index af7450619..b3c737979 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -273,6 +273,7 @@
273 <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> 273 <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string>
274 <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string> 274 <string name="performance_warning">Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.</string>
275 <string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string> 275 <string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string>
276 <string name="memory_formatted">%1$s %2$s</string>
276 277
277 <!-- Region Names --> 278 <!-- Region Names -->
278 <string name="region_japan">Japan</string> 279 <string name="region_japan">Japan</string>