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 f0a6753a9..b1771b424 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
@@ -27,13 +27,13 @@ import android.view.MotionEvent
import android.view.Surface
import android.view.View
import android.view.inputmethod.InputMethodManager
+import android.widget.Toast
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.navigation.fragment.NavHostFragment
-import kotlin.math.roundToInt
import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
@@ -44,8 +44,10 @@ import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler
+import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.NfcReader
import org.yuzu.yuzu_emu.utils.ThemeHelper
+import kotlin.math.roundToInt
class EmulationActivity : AppCompatActivity(), SensorEventListener {
private lateinit var binding: ActivityEmulationBinding
@@ -102,6 +104,19 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
inputHandler = InputHandler()
inputHandler.initialize()
+ val memoryUtil = MemoryUtil(this)
+ if (memoryUtil.isLessThan(8, MemoryUtil.Gb)) {
+ Toast.makeText(
+ this,
+ getString(
+ R.string.device_memory_inadequate,
+ memoryUtil.getDeviceRAM(),
+ "8 ${getString(R.string.memory_gigabyte)}"
+ ),
+ Toast.LENGTH_LONG
+ ).show()
+ }
+
// Start a foreground service to prevent the app from getting killed in the background
val startIntent = Intent(this, ForegroundService::class.java)
startForegroundService(startIntent)
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
new file mode 100644
index 000000000..18e5fa0b0
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/MemoryUtil.kt
@@ -0,0 +1,59 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.utils
+
+import android.app.ActivityManager
+import android.content.Context
+import org.yuzu.yuzu_emu.R
+import java.util.Locale
+
+class MemoryUtil(val context: Context) {
+
+ private val Long.floatForm: String
+ get() = String.format(Locale.ROOT, "%.2f", this.toDouble())
+
+ private fun bytesToSizeUnit(size: Long): String {
+ return when {
+ size < Kb -> "${size.floatForm} ${context.getString(R.string.memory_byte)}"
+ size < Mb -> "${(size / Kb).floatForm} ${context.getString(R.string.memory_kilobyte)}"
+ size < Gb -> "${(size / Mb).floatForm} ${context.getString(R.string.memory_megabyte)}"
+ size < Tb -> "${(size / Gb).floatForm} ${context.getString(R.string.memory_gigabyte)}"
+ size < Pb -> "${(size / Tb).floatForm} ${context.getString(R.string.memory_terabyte)}"
+ size < Eb -> "${(size / Pb).floatForm} ${context.getString(R.string.memory_petabyte)}"
+ else -> "${(size / Eb).floatForm} ${context.getString(R.string.memory_exabyte)}"
+ }
+ }
+
+ private val totalMemory =
+ with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
+ val memInfo = ActivityManager.MemoryInfo()
+ getMemoryInfo(memInfo)
+ memInfo.totalMem
+ }
+
+ fun isLessThan(minimum: Int, size: Long): Boolean {
+ return when (size) {
+ Kb -> totalMemory < Mb && totalMemory < minimum
+ Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
+ Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
+ Tb -> totalMemory < Pb && (totalMemory / Tb) < minimum
+ Pb -> totalMemory < Eb && (totalMemory / Pb) < minimum
+ Eb -> totalMemory / Eb < minimum
+ else -> totalMemory < Kb && totalMemory < minimum
+ }
+ }
+
+ fun getDeviceRAM(): String {
+ return bytesToSizeUnit(totalMemory)
+ }
+
+ companion object {
+ const val Kb: Long = 1024
+ const val Mb = Kb * 1024
+ const val Gb = Mb * 1024
+ const val Tb = Gb * 1024
+ const val Pb = Tb * 1024
+ const val Eb = Pb * 1024
+ }
+}
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index cc1d8c39d..85fc682f2 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -270,6 +270,7 @@
Fatal Error
A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.
Turning off this setting will significantly reduce emulation performance! For the best experience, it is recommended that you leave this setting enabled.
+ Device RAM: %1$s\nRecommended: %2$s
Japan
@@ -300,6 +301,15 @@
Traditional Chinese (正體中文)
Brazilian Portuguese (Português do Brasil)
+
+ Byte
+ KB
+ MB
+ GB
+ TB
+ PB
+ EB
+
Vulkan
None