diff options
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 import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat import androidx.navigation.fragment.NavHostFragment +import androidx.preference.PreferenceManager import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting import org.yuzu.yuzu_emu.features.settings.model.IntSetting +import org.yuzu.yuzu_emu.features.settings.model.Settings import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.utils.ControllerMappingHelper @@ -47,6 +50,7 @@ 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 java.text.NumberFormat import kotlin.math.roundToInt class EmulationActivity : AppCompatActivity(), SensorEventListener { @@ -106,17 +110,26 @@ 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() + val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) + if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) { + if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) { + Toast.makeText( + this, + getString( + R.string.device_memory_inadequate, + MemoryUtil.getDeviceRAM(), + getString( + R.string.memory_formatted, + NumberFormat.getInstance().format(MemoryUtil.REQUIRED_MEMORY), + getString(R.string.memory_gigabyte) + ) + ), + Toast.LENGTH_LONG + ).show() + preferences.edit() + .putBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, true) + .apply() + } } // 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 { const val SECTION_THEME = "Theme" const val SECTION_DEBUG = "Debug" + const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" + const val PREF_OVERLAY_INIT = "OverlayInit" const val PREF_CONTROL_SCALE = "controlScale" 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 import android.app.ActivityManager import android.content.Context +import android.os.Build import org.yuzu.yuzu_emu.R +import org.yuzu.yuzu_emu.YuzuApplication import java.util.Locale +import kotlin.math.ceil -class MemoryUtil(val context: Context) { +object MemoryUtil { + private val context get() = YuzuApplication.appContext - private val Long.floatForm: String - get() = String.format(Locale.ROOT, "%.2f", this.toDouble()) + private val Float.hundredths: String + get() = String.format(Locale.ROOT, "%.2f", this) - 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)}" + // Required total system memory + const val REQUIRED_MEMORY = 8 + + const val Kb: Float = 1024F + 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 + + private fun bytesToSizeUnit(size: Float): String = + when { + size < Kb -> { + context.getString( + R.string.memory_formatted, + size.hundredths, + context.getString(R.string.memory_byte) + ) + } + size < Mb -> { + context.getString( + R.string.memory_formatted, + (size / Kb).hundredths, + context.getString(R.string.memory_kilobyte) + ) + } + size < Gb -> { + context.getString( + R.string.memory_formatted, + (size / Mb).hundredths, + context.getString(R.string.memory_megabyte) + ) + } + size < Tb -> { + context.getString( + R.string.memory_formatted, + (size / Gb).hundredths, + context.getString(R.string.memory_gigabyte) + ) + } + size < Pb -> { + context.getString( + R.string.memory_formatted, + (size / Tb).hundredths, + context.getString(R.string.memory_terabyte) + ) + } + size < Eb -> { + context.getString( + R.string.memory_formatted, + (size / Pb).hundredths, + context.getString(R.string.memory_petabyte) + ) + } + else -> { + context.getString( + R.string.memory_formatted, + (size / Eb).hundredths, + context.getString(R.string.memory_exabyte) + ) + } } - } - private val totalMemory = - with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { + // Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for + // the potential error created by memInfo.totalMem + private val totalMemory: Float + get() { val memInfo = ActivityManager.MemoryInfo() - getMemoryInfo(memInfo) - memInfo.totalMem + with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) { + getMemoryInfo(memInfo) + } + + return ceil( + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + memInfo.advertisedMem.toFloat() + } else { + memInfo.totalMem.toFloat() + } + ) } - fun isLessThan(minimum: Int, size: Long): Boolean { - return when (size) { + fun isLessThan(minimum: Int, size: Float): Boolean = + when (size) { Kb -> totalMemory < Mb && totalMemory < minimum Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum @@ -42,18 +108,6 @@ class MemoryUtil(val context: Context) { 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 - } + + fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory) } 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 @@ <string name="fatal_error_message">A fatal error occurred. Check the log for details.\nContinuing emulation may result in crashes and bugs.</string> <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> <string name="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string> + <string name="memory_formatted">%1$s %2$s</string> <!-- Region Names --> <string name="region_japan">Japan</string> |