[android] add power consumption and battery status overlay (#22)

- adds the option to show power draw in amperes
- shows if the battery is charging

Signed-off-by: Aleksandr Popovich <alekpopo@pm.me>

Co-authored-by: Aleksandr Popovich <alekpopo@pm.me>
Reviewed-on: https://git.bixed.xyz/Bix/eden/pulls/22
This commit is contained in:
crueter 2025-07-08 21:12:02 +00:00
parent 9d60900ecf
commit 347d54bc26
10 changed files with 156 additions and 69 deletions

View file

@ -58,7 +58,9 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
SHOW_APP_RAM_USAGE("show_app_ram_usage"),
SHOW_SYSTEM_RAM_USAGE("show_system_ram_usage"),
SHOW_BAT_TEMPERATURE("show_bat_temperature"),
SHOW_POWER_INFO("show_power_info"),
SHOW_SHADERS_BUILDING("show_shaders_building"),
DEBUG_FLUSH_BY_LINE("flush_lines"),
USE_LRU_CACHE("use_lru_cache"),;

View file

@ -42,7 +42,7 @@ enum class IntSetting(override val key: String) : AbstractIntSetting {
FAST_CPU_TIME("fast_cpu_time"),
CPU_TICKS("cpu_ticks"),
FAST_GPU_TIME("fast_gpu_time"),
BAT_TEMPERATURE_UNIT("bat_temperature_unit"),
CABINET_APPLET("cabinet_applet_mode"),
CONTROLLER_APPLET("controller_applet_mode"),
DATA_ERASE_APPLET("data_erase_applet_mode"),

View file

@ -78,7 +78,7 @@ abstract class SettingsItem(
val needsRuntimeGlobal: Boolean
get() = NativeLibrary.isRunning() && !setting.global &&
!NativeConfig.isPerGameConfigLoaded()
!NativeConfig.isPerGameConfigLoaded()
val clearable: Boolean
get() = !setting.global && NativeConfig.isPerGameConfigLoaded()
@ -260,12 +260,12 @@ abstract class SettingsItem(
)
)
put(
SwitchSetting(
BooleanSetting.CORE_SYNC_CORE_SPEED,
titleId = R.string.use_sync_core,
descriptionId = R.string.use_sync_core_description
)
)
SwitchSetting(
BooleanSetting.CORE_SYNC_CORE_SPEED,
titleId = R.string.use_sync_core,
descriptionId = R.string.use_sync_core_description
)
)
put(
SingleChoiceSetting(
@ -443,6 +443,21 @@ abstract class SettingsItem(
descriptionId = R.string.show_bat_temperature_description
)
)
put(
SingleChoiceSetting(
IntSetting.BAT_TEMPERATURE_UNIT,
R.string.bat_temperature_unit,
choicesId = R.array.temperatureUnitEntries,
valuesId = R.array.temperatureUnitValues
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_POWER_INFO,
R.string.show_power_info,
descriptionId = R.string.show_power_info_description
)
)
put(
SwitchSetting(
BooleanSetting.SHOW_SHADERS_BUILDING,
@ -688,12 +703,12 @@ abstract class SettingsItem(
)
)
put(
SwitchSetting(
BooleanSetting.USE_AUTO_STUB,
titleId = R.string.use_auto_stub,
descriptionId = R.string.use_auto_stub_description
)
)
SwitchSetting(
BooleanSetting.USE_AUTO_STUB,
titleId = R.string.use_auto_stub,
descriptionId = R.string.use_auto_stub_description
)
)
put(
SwitchSetting(
BooleanSetting.CPU_DEBUG_MODE,
@ -705,7 +720,7 @@ abstract class SettingsItem(
val fastmem = object : AbstractBooleanSetting {
override fun getBoolean(needsGlobal: Boolean): Boolean =
BooleanSetting.FASTMEM.getBoolean() &&
BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean()
BooleanSetting.FASTMEM_EXCLUSIVES.getBoolean()
override fun setBoolean(value: Boolean) {
BooleanSetting.FASTMEM.setBoolean(value)
@ -720,7 +735,7 @@ abstract class SettingsItem(
override var global: Boolean
get() {
return BooleanSetting.FASTMEM.global &&
BooleanSetting.FASTMEM_EXCLUSIVES.global
BooleanSetting.FASTMEM_EXCLUSIVES.global
}
set(value) {
BooleanSetting.FASTMEM.global = value

View file

@ -260,6 +260,8 @@ class SettingsFragmentPresenter(
add(BooleanSetting.SHOW_APP_RAM_USAGE.key)
add(BooleanSetting.SHOW_SYSTEM_RAM_USAGE.key)
add(BooleanSetting.SHOW_BAT_TEMPERATURE.key)
add(IntSetting.BAT_TEMPERATURE_UNIT.key)
add(BooleanSetting.SHOW_POWER_INFO.key)
add(BooleanSetting.SHOW_SHADERS_BUILDING.key)
}
}

View file

@ -17,6 +17,7 @@ import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.net.Uri
import android.os.BatteryManager
import android.os.BatteryManager.*
import android.os.Build
import android.os.Bundle
import android.os.Handler
@ -574,12 +575,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
if (emulationViewModel.emulationStarted.value &&
!emulationViewModel.isEmulationStopping.value
) {
val needsGlobal = NativeConfig.isPerGameConfigLoaded()
sb.setLength(0)
val perfStats = NativeLibrary.getPerfStats()
val actualFps = perfStats[FPS]
if (BooleanSetting.SHOW_FPS.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.SHOW_FPS.getBoolean(needsGlobal)) {
val enableFrameInterpolation =
BooleanSetting.FRAME_INTERPOLATION.getBoolean()
// val enableFrameSkipping = BooleanSetting.FRAME_SKIPPING.getBoolean()
@ -597,7 +599,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
sb.append(fpsText)
}
if (BooleanSetting.SHOW_FRAMETIME.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.SHOW_FRAMETIME.getBoolean(needsGlobal)) {
if (sb.isNotEmpty()) sb.append(" | ")
sb.append(
String.format(
@ -607,13 +609,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
)
}
if (BooleanSetting.SHOW_APP_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.SHOW_APP_RAM_USAGE.getBoolean(needsGlobal)) {
if (sb.isNotEmpty()) sb.append(" | ")
val appRamUsage = File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000
val appRamUsage =
File("/proc/self/statm").readLines()[0].split(' ')[1].toLong() * 4096 / 1000000
sb.append(getString(R.string.process_ram, appRamUsage))
}
if (BooleanSetting.SHOW_SYSTEM_RAM_USAGE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.SHOW_SYSTEM_RAM_USAGE.getBoolean(needsGlobal)) {
if (sb.isNotEmpty()) sb.append(" | ")
context?.let { ctx ->
val activityManager =
@ -625,16 +628,35 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
}
}
if (BooleanSetting.SHOW_BAT_TEMPERATURE.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.SHOW_BAT_TEMPERATURE.getBoolean(needsGlobal)) {
if (sb.isNotEmpty()) sb.append(" | ")
val batteryTemp = getBatteryTemperature()
val tempF = celsiusToFahrenheit(batteryTemp)
sb.append(String.format("%.1f°C/%.1f°F", batteryTemp, tempF))
when (IntSetting.BAT_TEMPERATURE_UNIT.getInt(needsGlobal)) {
0 -> sb.append(String.format("%.1f°C", batteryTemp))
1 -> sb.append(String.format("%.1f°F", celsiusToFahrenheit(batteryTemp)))
}
}
if (BooleanSetting.SHOW_POWER_INFO.getBoolean(needsGlobal)) {
if (sb.isNotEmpty()) sb.append(" | ")
val battery: BatteryManager =
requireContext().getSystemService(Context.BATTERY_SERVICE) as BatteryManager
val capacity = battery.getIntProperty(BATTERY_PROPERTY_CAPACITY)
val nowUAmps = battery.getIntProperty(BATTERY_PROPERTY_CURRENT_NOW)
sb.append(String.format("%.1fA (%d%%)", nowUAmps / 1000000.0, capacity))
if (battery.isCharging || nowUAmps > 0.0) {
sb.append(" ${getString(R.string.charging)}")
}
}
val shadersBuilding = NativeLibrary.getShadersBuilding()
if (BooleanSetting.SHOW_SHADERS_BUILDING.getBoolean(NativeConfig.isPerGameConfigLoaded()) && shadersBuilding != 0) {
if (BooleanSetting.SHOW_SHADERS_BUILDING.getBoolean(needsGlobal) && shadersBuilding != 0) {
if (sb.isNotEmpty()) sb.append(" | ")
val prefix = getString(R.string.shaders_prefix)
@ -642,7 +664,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
sb.append(String.format("$prefix %d $suffix", shadersBuilding))
}
if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(NativeConfig.isPerGameConfigLoaded())) {
if (BooleanSetting.PERF_OVERLAY_BACKGROUND.getBoolean(needsGlobal)) {
binding.showStatsOverlayText.setBackgroundResource(R.color.yuzu_transparent_black)
} else {
binding.showStatsOverlayText.setBackgroundResource(0)

View file

@ -9,6 +9,7 @@
#include <common/settings_common.h>
#include "common/common_types.h"
#include "common/settings_setting.h"
#include "common/settings_enums.h"
namespace AndroidSettings {
@ -79,9 +80,10 @@ namespace AndroidSettings {
Settings::Specialization::Paired, true,
true};
Settings::Setting<bool> perf_overlay_background{linkage, false, "perf_overlay_background",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true,
true,
&show_performance_overlay};
Settings::Setting<s32> perf_overlay_position{linkage, 0, "perf_overlay_position",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
@ -107,10 +109,23 @@ namespace AndroidSettings {
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<Settings::TemperatureUnits> bat_temperature_unit{linkage,
Settings::TemperatureUnits::Celsius,
"bat_temperature_unit",
Settings::Category::Overlay,
Settings::Specialization::Default,
true, true,
&show_bat_temperature};
Settings::Setting<bool> show_power_info{linkage, false, "show_power_info",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<bool> show_shaders_building{linkage, true, "show_shaders_building",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
Settings::Category::Overlay};
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen",
@ -125,14 +140,14 @@ namespace AndroidSettings {
Settings::Specialization::Paired, true, true};
Settings::Setting<bool> show_device_model{linkage, true, "show_device_model",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<bool> show_gpu_model{linkage, true, "show_gpu_model",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<bool> show_soc_model{linkage, true, "show_soc_model",
Settings::Category::Overlay,
@ -140,18 +155,19 @@ namespace AndroidSettings {
&show_soc_overlay};
Settings::Setting<bool> show_fw_version{linkage, true, "show_firmware_version",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_performance_overlay};
Settings::Setting<bool> soc_overlay_background{linkage, false, "soc_overlay_background",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true,
true,
&show_soc_overlay};
Settings::Setting<s32> soc_overlay_position{linkage, 2, "soc_overlay_position",
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Category::Overlay,
Settings::Specialization::Default, true, true,
&show_soc_overlay};
Settings::Setting<bool> dont_show_eden_veil_warning{linkage, false,
"dont_show_eden_veil_warning",

View file

@ -14,6 +14,8 @@
<string name="shaders_prefix">Зграда</string>
<string name="shaders_suffix">Схадер (с)</string>
<string name="system_info_label">Систем:</string>
<string name="charging">(Пуњење)</string>
<string name="show_stats_overlay">Покажи Статистика перформанси Статистика</string>
<string name="stats_overlay_customization">Прилагођавање</string>
<string name="stats_overlay_items">Видљивост</string>
@ -31,7 +33,10 @@
<string name="show_system_ram_usage">Прикажи употребу система меморије</string>
<string name="show_system_ram_usage_description">Прикажите износ РАМ-а који користи систем</string>
<string name="show_bat_temperature">Прикажи температуру батерије</string>
<string name="show_bat_temperature_description">Прикажи тренутну температуру батерије у Целзијусу и Фахренхеиту</string>
<string name="show_bat_temperature_description">Прикажи тренутну температуру батерије</string>
<string name="bat_temperature_unit">Јединице за температуру батерије</string>
<string name="show_power_info">Прикажи информације о батерији</string>
<string name="show_power_info_description">Приказ тренутне потрошње енергије и преостали капацитет батерије</string>
<string name="show_shaders_building">Прикажи Схадерс Буилдинг</string>
<string name="show_shaders_building_description">Прикажи тренутни број саграђених Схадера</string>
<string name="overlay_position">Положај прекривања</string>
@ -98,11 +103,11 @@
<string name="memory_layout">Изглед меморије</string>
<string name="memory_layout_description">(Експериментално) Промените изглед емулираног меморије. Ово постављање неће повећати перформансе, али може помоћи у играма које користе високе резолуције путем модова. Не користите на телефонима са 8 ГБ РАМ-а или мање. Ради само на динамичком (ЈИТ) бацкенд-у.</string>
<string name="sample_shading">Семпловање сенчења</string>
<string name="sample_shading_description">Омогућава фрагмент шејдеру да се извршава по узорку у вишеузорачном фрагменту уместо једном по фрагменту. Побољшава квалитет графике на рачун перформанси. Само Vulkan 1.1+ уређаји подржавају ову екстензију.</string>
<string name="custom_cpu_ticks">Прилагођени CPU тактови</string>
<string name="custom_cpu_ticks_description">Поставите прилагођену вредност CPU тактова. Веће вредности могу повећати перформансе, али могу изазвати залеђивање игре. Препоручује се опсег 7721000.</string>
<string name="cpu_ticks">Тактови</string>
<string name="sample_shading">Семпловање сенчења</string>
<string name="sample_shading_description">Омогућава фрагмент шејдеру да се извршава по узорку у вишеузорачном фрагменту уместо једном по фрагменту. Побољшава квалитет графике на рачун перформанси. Само Vulkan 1.1+ уређаји подржавају ову екстензију.</string>
<string name="custom_cpu_ticks">Прилагођени CPU тактови</string>
<string name="custom_cpu_ticks_description">Поставите прилагођену вредност CPU тактова. Веће вредности могу повећати перформансе, али могу изазвати залеђивање игре. Препоручује се опсег 7721000.</string>
<string name="cpu_ticks">Тактови</string>
<!-- Shader Backend -->
<string name="shader_backend">Схадер Бацкенд</string>
@ -205,23 +210,23 @@
<string name="multiplayer_no_game">Није пронађена није пронађена игара</string>
<string name="multiplayer_preferred_game_name_invalid">Морате одабрати преферирану игру да бисте угостили собу.</string>
<string name="multiplayer_token_error">Мора бити дугачко 48 знакова и садржати само мала слова a-z</string>
<string name="multiplayer_lobby_type">Тип лобија</string>
<string name="multiplayer_public_visibility">Јавно</string>
<string name="multiplayer_unlisted_visibility">Неприказано</string>
<string name="multiplayer_name_invalid">Име је прекратко</string>
<string name="multiplayer_address_invalid">Неисправна адреса</string>
<string name="multiplayer_username_error">Мора бити између 420 знакова</string>
<string name="multiplayer_lobby_type">Тип лобија</string>
<string name="multiplayer_public_visibility">Јавно</string>
<string name="multiplayer_unlisted_visibility">Неприказано</string>
<string name="multiplayer_name_invalid">Име је прекратко</string>
<string name="multiplayer_address_invalid">Неисправна адреса</string>
<string name="multiplayer_username_error">Мора бити између 420 знакова</string>
<string name="cancel">Отказати</string>
<string name="ok">У реду</string>
<string name="refresh">Освежити</string>
<string name="room_list">Листа соба</string>
<string name="multiplayer_joining">Придружујем се…</string>
<string name="multiplayer_creating">Креирам…</string>
<string name="multiplayer_required">Обавезно</string>
<string name="multiplayer_token_required">Потребан је веб токен, идите на Напредне поставке -> Систем -> Мрежа</string>
<string name="multiplayer_ip_error">Неисправан ИП формат</string>
<string name="multiplayer_port_error">Мора бити између 1 и 65535</string>
<string name="multiplayer_room_name_error">Мора бити између 3 и 20 знакова</string>
<string name="multiplayer_creating">Креирам…</string>
<string name="multiplayer_required">Обавезно</string>
<string name="multiplayer_token_required">Потребан је веб токен, идите на Напредне поставке -> Систем -> Мрежа</string>
<string name="multiplayer_ip_error">Неисправан ИП формат</string>
<string name="multiplayer_port_error">Мора бити између 1 и 65535</string>
<string name="multiplayer_room_name_error">Мора бити између 3 и 20 знакова</string>
<!-- Setup strings -->
<string name="welcome">Добродошли!</string>
@ -428,16 +433,16 @@
<!-- Network settings strings -->
<string name="generate">Генериши</string>
<string name="web_username">Веб корисничко име</string>
<string name="web_username_description">Корисничко име које ће бити приказано у мултиплејер лобијима. Мора бити дугачко 420 знакова.</string>
<string name="web_username">Веб корисничко име</string>
<string name="web_username_description">Корисничко име које ће бити приказано у мултиплејер лобијима. Мора бити дугачко 420 знакова.</string>
<string name="web_token">Веб токен</string>
<string name="web_token_description">Веб токен који се користи за стварање јавних лобија. То је низ од 48 знакова који садржи само мала слова А-З.</string>
<string name="network">Мрежа</string>
<!-- Graphics settings strings -->
<string name="backend">Бекенд</string>
<string name="display">Приказ</string>
<string name="processing">Постпроцесирање</string>
<string name="display">Приказ</string>
<string name="processing">Постпроцесирање</string>
<string name="frame_skipping">ВИП: Фрамескип</string>
<string name="frame_skipping_description">Пребацивање оквира прескакање да бисте побољшали перформансе смањењем броја пружених оквира. Ова функција се и даље ради и биће омогућена у будућим издањима.</string>
<string name="renderer_accuracy">Ниво тачности</string>
@ -791,6 +796,10 @@
<string name="gpu_medium">Средња (256)</string>
<string name="gpu_high">Висок (512)</string>
<!-- Temperature Units -->
<string name="temperature_celsius">Целзијус</string>
<string name="temperature_fahrenheit">Фаренхајт</string>
<!-- Language Names -->
<string name="language_japanese" translatable="false">日本語</string>
<string name="language_english" translatable="false">English</string>
@ -979,8 +988,8 @@
<string name="swkbd_applet">Софтверска тастатура</string>
<string name="airplane_mode">Авионски режим</string>
<string name="airplane_mode_description">Прослеђује авионски режим на Switch OS</string>
<string name="airplane_mode">Авионски режим</string>
<string name="airplane_mode_description">Прослеђује авионски режим на Switch OS</string>
<!-- Licenses screen strings -->
<string name="licenses">Лиценце</string>

View file

@ -471,4 +471,14 @@
<item>1</item>
<item>2</item>
</integer-array>
<string-array name="temperatureUnitEntries">
<item>@string/temperature_celsius</item>
<item>@string/temperature_fahrenheit</item>
</string-array>
<integer-array name="temperatureUnitValues">
<item>0</item>
<item>1</item>
</integer-array>
</resources>

View file

@ -14,6 +14,8 @@
<string name="process_ram">Process RAM: %1$d MB</string>
<string name="shaders_prefix">Building</string>
<string name="shaders_suffix">Shader(s)</string>
<string name="charging">(Charging)</string>
<string name="system_info_label">System:</string>
<string name="show_stats_overlay">Show Performance Stats Overlay</string>
<string name="stats_overlay_customization">Customization</string>
@ -32,7 +34,10 @@
<string name="show_system_ram_usage">Show System Memory Usage</string>
<string name="show_system_ram_usage_description">Display the amount of RAM used by the system</string>
<string name="show_bat_temperature">Show Battery Temperature</string>
<string name="show_bat_temperature_description">Display current Battery temperature in Celsius and Fahrenheit</string>
<string name="show_bat_temperature_description">Display current battery temperature</string>
<string name="bat_temperature_unit">Battery Temperature Units</string>
<string name="show_power_info">Show Battery Info</string>
<string name="show_power_info_description">Display current power draw and remaining capacity on battery</string>
<string name="show_shaders_building">Show Shaders Building</string>
<string name="show_shaders_building_description">Display current number of shaders being built</string>
<string name="overlay_position">Overlay Position</string>
@ -818,6 +823,10 @@
<string name="gpu_medium">Medium (256)</string>
<string name="gpu_high">High (512)</string>
<!-- Temperature Units -->
<string name="temperature_celsius">Celsius</string>
<string name="temperature_fahrenheit">Fahrenheit</string>
<!-- Language Names -->
<string name="language_japanese" translatable="false">日本語</string>
<string name="language_english" translatable="false">English</string>

View file

@ -178,6 +178,8 @@ ENUM(SpirvOptimizeMode, Never, OnLoad, Always);
ENUM(GpuOverclock, Low, Medium, High)
ENUM(TemperatureUnits, Celsius, Fahrenheit)
template <typename Type>
inline std::string CanonicalizeEnum(Type id) {
const auto group = EnumMetadata<Type>::Canonicalizations();