diff options
| author | 2023-07-02 11:29:08 -0400 | |
|---|---|---|
| committer | 2023-07-02 11:29:08 -0400 | |
| commit | 657ab0287d1e7aa42ac01c49c26768e21b2088f7 (patch) | |
| tree | a1ad316c11506d78f8f419853a9761630b79a393 /src | |
| parent | Merge pull request #10942 from FernandoS27/android-is-a-pain-in-the-a-- (diff) | |
| parent | android: Show memory warning once (diff) | |
| download | yuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.tar.gz yuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.tar.xz yuzu-657ab0287d1e7aa42ac01c49c26768e21b2088f7.zip | |
Merge pull request #10949 from t895/memory-requirements
android: Rework MemoryUtil
Diffstat (limited to 'src')
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 | |||
| 34 | import androidx.core.view.WindowInsetsCompat | 34 | import androidx.core.view.WindowInsetsCompat |
| 35 | import androidx.core.view.WindowInsetsControllerCompat | 35 | import androidx.core.view.WindowInsetsControllerCompat |
| 36 | import androidx.navigation.fragment.NavHostFragment | 36 | import androidx.navigation.fragment.NavHostFragment |
| 37 | import androidx.preference.PreferenceManager | ||
| 37 | import org.yuzu.yuzu_emu.NativeLibrary | 38 | import org.yuzu.yuzu_emu.NativeLibrary |
| 38 | import org.yuzu.yuzu_emu.R | 39 | import org.yuzu.yuzu_emu.R |
| 40 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 39 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding | 41 | import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding |
| 40 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 42 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 41 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 43 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 44 | import org.yuzu.yuzu_emu.features.settings.model.Settings | ||
| 42 | import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | 45 | import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel |
| 43 | import org.yuzu.yuzu_emu.model.Game | 46 | import org.yuzu.yuzu_emu.model.Game |
| 44 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | 47 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper |
| @@ -47,6 +50,7 @@ import org.yuzu.yuzu_emu.utils.InputHandler | |||
| 47 | import org.yuzu.yuzu_emu.utils.MemoryUtil | 50 | import org.yuzu.yuzu_emu.utils.MemoryUtil |
| 48 | import org.yuzu.yuzu_emu.utils.NfcReader | 51 | import org.yuzu.yuzu_emu.utils.NfcReader |
| 49 | import org.yuzu.yuzu_emu.utils.ThemeHelper | 52 | import org.yuzu.yuzu_emu.utils.ThemeHelper |
| 53 | import java.text.NumberFormat | ||
| 50 | import kotlin.math.roundToInt | 54 | import kotlin.math.roundToInt |
| 51 | 55 | ||
| 52 | class EmulationActivity : AppCompatActivity(), SensorEventListener { | 56 | class 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 | ||
| 6 | import android.app.ActivityManager | 6 | import android.app.ActivityManager |
| 7 | import android.content.Context | 7 | import android.content.Context |
| 8 | import android.os.Build | ||
| 8 | import org.yuzu.yuzu_emu.R | 9 | import org.yuzu.yuzu_emu.R |
| 10 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 9 | import java.util.Locale | 11 | import java.util.Locale |
| 12 | import kotlin.math.ceil | ||
| 10 | 13 | ||
| 11 | class MemoryUtil(val context: Context) { | 14 | object 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> |