Merge pull request #10949 from t895/memory-requirements
android: Rework MemoryUtil
This commit is contained in:
commit
657ab0287d
4 changed files with 113 additions and 43 deletions
|
@ -34,11 +34,14 @@ import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.navigation.fragment.NavHostFragment
|
import androidx.navigation.fragment.NavHostFragment
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
import org.yuzu.yuzu_emu.NativeLibrary
|
import org.yuzu.yuzu_emu.NativeLibrary
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
|
import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
|
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.IntSetting
|
||||||
|
import org.yuzu.yuzu_emu.features.settings.model.Settings
|
||||||
import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
|
import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
|
||||||
import org.yuzu.yuzu_emu.model.Game
|
import org.yuzu.yuzu_emu.model.Game
|
||||||
import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
|
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.MemoryUtil
|
||||||
import org.yuzu.yuzu_emu.utils.NfcReader
|
import org.yuzu.yuzu_emu.utils.NfcReader
|
||||||
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
import org.yuzu.yuzu_emu.utils.ThemeHelper
|
||||||
|
import java.text.NumberFormat
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
|
@ -106,17 +110,26 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
|
||||||
inputHandler = InputHandler()
|
inputHandler = InputHandler()
|
||||||
inputHandler.initialize()
|
inputHandler.initialize()
|
||||||
|
|
||||||
val memoryUtil = MemoryUtil(this)
|
val preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
|
||||||
if (memoryUtil.isLessThan(8, MemoryUtil.Gb)) {
|
if (!preferences.getBoolean(Settings.PREF_MEMORY_WARNING_SHOWN, false)) {
|
||||||
|
if (MemoryUtil.isLessThan(MemoryUtil.REQUIRED_MEMORY, MemoryUtil.Gb)) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
getString(
|
getString(
|
||||||
R.string.device_memory_inadequate,
|
R.string.device_memory_inadequate,
|
||||||
memoryUtil.getDeviceRAM(),
|
MemoryUtil.getDeviceRAM(),
|
||||||
"8 ${getString(R.string.memory_gigabyte)}"
|
getString(
|
||||||
|
R.string.memory_formatted,
|
||||||
|
NumberFormat.getInstance().format(MemoryUtil.REQUIRED_MEMORY),
|
||||||
|
getString(R.string.memory_gigabyte)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
).show()
|
).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
|
// Start a foreground service to prevent the app from getting killed in the background
|
||||||
|
|
|
@ -110,6 +110,8 @@ class Settings {
|
||||||
const val SECTION_THEME = "Theme"
|
const val SECTION_THEME = "Theme"
|
||||||
const val SECTION_DEBUG = "Debug"
|
const val SECTION_DEBUG = "Debug"
|
||||||
|
|
||||||
|
const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown"
|
||||||
|
|
||||||
const val PREF_OVERLAY_INIT = "OverlayInit"
|
const val PREF_OVERLAY_INIT = "OverlayInit"
|
||||||
const val PREF_CONTROL_SCALE = "controlScale"
|
const val PREF_CONTROL_SCALE = "controlScale"
|
||||||
const val PREF_CONTROL_OPACITY = "controlOpacity"
|
const val PREF_CONTROL_OPACITY = "controlOpacity"
|
||||||
|
|
|
@ -5,35 +5,101 @@ package org.yuzu.yuzu_emu.utils
|
||||||
|
|
||||||
import android.app.ActivityManager
|
import android.app.ActivityManager
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
import org.yuzu.yuzu_emu.R
|
import org.yuzu.yuzu_emu.R
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication
|
||||||
import java.util.Locale
|
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
|
private val Float.hundredths: String
|
||||||
get() = String.format(Locale.ROOT, "%.2f", this.toDouble())
|
get() = String.format(Locale.ROOT, "%.2f", this)
|
||||||
|
|
||||||
private fun bytesToSizeUnit(size: Long): String {
|
// Required total system memory
|
||||||
return when {
|
const val REQUIRED_MEMORY = 8
|
||||||
size < Kb -> "${size.floatForm} ${context.getString(R.string.memory_byte)}"
|
|
||||||
size < Mb -> "${(size / Kb).floatForm} ${context.getString(R.string.memory_kilobyte)}"
|
const val Kb: Float = 1024F
|
||||||
size < Gb -> "${(size / Mb).floatForm} ${context.getString(R.string.memory_megabyte)}"
|
const val Mb = Kb * 1024
|
||||||
size < Tb -> "${(size / Gb).floatForm} ${context.getString(R.string.memory_gigabyte)}"
|
const val Gb = Mb * 1024
|
||||||
size < Pb -> "${(size / Tb).floatForm} ${context.getString(R.string.memory_terabyte)}"
|
const val Tb = Gb * 1024
|
||||||
size < Eb -> "${(size / Pb).floatForm} ${context.getString(R.string.memory_petabyte)}"
|
const val Pb = Tb * 1024
|
||||||
else -> "${(size / Eb).floatForm} ${context.getString(R.string.memory_exabyte)}"
|
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 =
|
// Devices are unlikely to have 0.5GB increments of memory so we'll just round up to account for
|
||||||
with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
|
// the potential error created by memInfo.totalMem
|
||||||
|
private val totalMemory: Float
|
||||||
|
get() {
|
||||||
val memInfo = ActivityManager.MemoryInfo()
|
val memInfo = ActivityManager.MemoryInfo()
|
||||||
|
with(context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager) {
|
||||||
getMemoryInfo(memInfo)
|
getMemoryInfo(memInfo)
|
||||||
memInfo.totalMem
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isLessThan(minimum: Int, size: Long): Boolean {
|
return ceil(
|
||||||
return when (size) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||||
|
memInfo.advertisedMem.toFloat()
|
||||||
|
} else {
|
||||||
|
memInfo.totalMem.toFloat()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isLessThan(minimum: Int, size: Float): Boolean =
|
||||||
|
when (size) {
|
||||||
Kb -> totalMemory < Mb && totalMemory < minimum
|
Kb -> totalMemory < Mb && totalMemory < minimum
|
||||||
Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
|
Mb -> totalMemory < Gb && (totalMemory / Mb) < minimum
|
||||||
Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
|
Gb -> totalMemory < Tb && (totalMemory / Gb) < minimum
|
||||||
|
@ -42,18 +108,6 @@ class MemoryUtil(val context: Context) {
|
||||||
Eb -> totalMemory / Eb < minimum
|
Eb -> totalMemory / Eb < minimum
|
||||||
else -> totalMemory < Kb && totalMemory < minimum
|
else -> totalMemory < Kb && totalMemory < minimum
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fun getDeviceRAM(): String {
|
fun getDeviceRAM(): String = bytesToSizeUnit(totalMemory)
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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="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="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="device_memory_inadequate">Device RAM: %1$s\nRecommended: %2$s</string>
|
||||||
|
<string name="memory_formatted">%1$s %2$s</string>
|
||||||
|
|
||||||
<!-- Region Names -->
|
<!-- Region Names -->
|
||||||
<string name="region_japan">Japan</string>
|
<string name="region_japan">Japan</string>
|
||||||
|
|
Loading…
Reference in a new issue