diff options
Diffstat (limited to 'src/android')
6 files changed, 95 insertions, 26 deletions
diff --git a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt index 895194db5..f781d10c1 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/features/settings/model/BooleanSetting.kt @@ -1,4 +1,5 @@  // SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: 2025 Citron Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later  package org.citron.citron_emu.features.settings.model @@ -27,6 +28,7 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {      SHOW_INPUT_OVERLAY("show_input_overlay"),      TOUCHSCREEN("touchscreen"),      SHOW_THERMAL_OVERLAY("show_thermal_overlay"), +    SHOW_RAM_OVERLAY("show_ram_overlay"),      USE_AUTO_STUB("use_auto_stub");      override fun getBoolean(needsGlobal: Boolean): Boolean = diff --git a/src/android/app/src/main/java/org/citron/citron_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/citron/citron_emu/fragments/EmulationFragment.kt index 93a15def9..f4678b603 100644 --- a/src/android/app/src/main/java/org/citron/citron_emu/fragments/EmulationFragment.kt +++ b/src/android/app/src/main/java/org/citron/citron_emu/fragments/EmulationFragment.kt @@ -1,4 +1,5 @@  // SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: 2025 Citron Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later  package org.citron.citron_emu.fragments @@ -11,9 +12,11 @@ import android.content.Intent  import android.content.IntentFilter  import android.content.pm.ActivityInfo  import android.content.res.Configuration +import android.graphics.Color  import android.net.Uri  import android.os.BatteryManager  import android.os.Bundle +import android.os.Debug  import android.os.Handler  import android.os.Looper  import android.os.PowerManager @@ -68,6 +71,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {      private var emulationActivity: EmulationActivity? = null      private var perfStatsUpdater: (() -> Unit)? = null      private var thermalStatsUpdater: (() -> Unit)? = null +    private var ramStatsUpdater: (() -> Unit)? = null      private var _binding: FragmentEmulationBinding? = null      private val binding get() = _binding!! @@ -83,6 +87,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {      private lateinit var powerManager: PowerManager +    private val ramStatsUpdateHandler = Handler(Looper.myLooper()!!) +      override fun onAttach(context: Context) {          super.onAttach(context)          if (context is EmulationActivity) { @@ -376,6 +382,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {                  // Setup overlays                  updateShowFpsOverlay()                  updateThermalOverlay() +                updateRamOverlay()              }          }          emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) { @@ -470,6 +477,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {      override fun onDestroyView() {          super.onDestroyView() +        if (ramStatsUpdater != null) { +            ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!) +        }          _binding = null      } @@ -552,8 +562,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {              emulationViewModel.emulationStarted.value &&              !emulationViewModel.isEmulationStopping.value          ) { -            // Get thermal status +            // Get thermal status for color              val thermalStatus = when (powerManager.currentThermalStatus) { +                PowerManager.THERMAL_STATUS_NONE -> 0f                  PowerManager.THERMAL_STATUS_LIGHT -> 0.25f                  PowerManager.THERMAL_STATUS_MODERATE -> 0.5f                  PowerManager.THERMAL_STATUS_SEVERE -> 0.75f @@ -563,34 +574,57 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {                  else -> 0f              } -            // Convert to Fahrenheit for additional info +            // Convert to Fahrenheit              val fahrenheit = (temperature * 9f / 5f) + 32f -            // Create progress bar using block elements -            val progressBarLength = 12 -            val filledBars = (thermalStatus * progressBarLength).toInt() -            val progressBar = buildString { -                append("│") // Left border -                repeat(filledBars) { append("█") } -                repeat(progressBarLength - filledBars) { append("░") } -                append("│") // Right border -                append(" ") -                append(String.format("%3d%%", (thermalStatus * 100).toInt())) -            } - -            // Color interpolation based on temperature (green at 30°C, red at 45°C) -            val normalizedTemp = ((temperature - 30f) / 15f).coerceIn(0f, 1f) -            val red = (normalizedTemp * 255).toInt() -            val green = ((1f - normalizedTemp) * 255).toInt() +            // Color based on thermal status (green to red) +            val red = (thermalStatus * 255).toInt() +            val green = ((1f - thermalStatus) * 255).toInt()              val color = android.graphics.Color.rgb(red, green, 0)              binding.showThermalsText.setTextColor(color) -            binding.showThermalsText.text = String.format( -                "%s\n%.1f°C • %.1f°F", -                progressBar, -                temperature, -                fahrenheit -            ) +            binding.showThermalsText.text = String.format("%.1f°C • %.1f°F", temperature, fahrenheit) +        } +    } + +    private fun updateRamOverlay() { +        val showOverlay = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean() +        binding.showRamText.setVisible(showOverlay) +        if (showOverlay) { +            ramStatsUpdater = { +                if (emulationViewModel.emulationStarted.value && +                    !emulationViewModel.isEmulationStopping.value +                ) { +                    val runtime = Runtime.getRuntime() +                    val nativeHeapSize = Debug.getNativeHeapSize() +                    val nativeHeapFreeSize = Debug.getNativeHeapFreeSize() +                    val nativeHeapUsed = nativeHeapSize - nativeHeapFreeSize + +                    val usedMemInMB = nativeHeapUsed / 1048576L +                    val maxMemInMB = nativeHeapSize / 1048576L +                    val percentUsed = (nativeHeapUsed.toFloat() / nativeHeapSize.toFloat() * 100f) + +                    // Color interpolation from green to red based on usage percentage +                    val normalizedUsage = (percentUsed / 100f).coerceIn(0f, 1f) +                    val red = (normalizedUsage * 255).toInt() +                    val green = ((1f - normalizedUsage) * 255).toInt() +                    val color = Color.rgb(red, green, 0) + +                    binding.showRamText.setTextColor(color) +                    binding.showRamText.text = String.format( +                        "\nRAM: %d/%d MB (%.1f%%)", +                        usedMemInMB, +                        maxMemInMB, +                        percentUsed +                    ) +                    ramStatsUpdateHandler.postDelayed(ramStatsUpdater!!, 1000) +                } +            } +            ramStatsUpdateHandler.post(ramStatsUpdater!!) +        } else { +            if (ramStatsUpdater != null) { +                ramStatsUpdateHandler.removeCallbacks(ramStatsUpdater!!) +            }          }      } @@ -723,6 +757,10 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {                  BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()              findItem(R.id.thermal_indicator).isChecked =                  BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean() +            findItem(R.id.ram_meter).apply { +                isChecked = BooleanSetting.SHOW_RAM_OVERLAY.getBoolean() +                isEnabled = false  // This grays out the option +            }              findItem(R.id.menu_rel_stick_center).isChecked =                  BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()              findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean() @@ -749,6 +787,11 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {                      true                  } +                R.id.ram_meter -> { +                    // Do nothing since it's disabled +                    true +                } +                  R.id.menu_edit_overlay -> {                      binding.drawerLayout.close()                      binding.surfaceInputOverlay.requestFocus() diff --git a/src/android/app/src/main/jni/android_settings.h b/src/android/app/src/main/jni/android_settings.h index 00baf86a9..2dba36990 100644 --- a/src/android/app/src/main/jni/android_settings.h +++ b/src/android/app/src/main/jni/android_settings.h @@ -1,4 +1,5 @@  // SPDX-FileCopyrightText: 2023 yuzu Emulator Project +// SPDX-FileCopyrightText: 2025 Citron Emulator Project  // SPDX-License-Identifier: GPL-2.0-or-later  #pragma once @@ -51,7 +52,7 @@ struct Values {      Settings::Setting<s32> theme{linkage, 0, "theme", Settings::Category::Android};      Settings::Setting<s32> theme_mode{linkage, -1, "theme_mode", Settings::Category::Android}; -    Settings::Setting<bool> black_backgrounds{linkage, false, "black_backgrounds", +    Settings::Setting<bool> black_backgrounds{linkage, true, "black_backgrounds",                                                Settings::Category::Android};      // Input/performance overlay settings @@ -67,8 +68,10 @@ struct Values {                                              Settings::Category::Overlay};      Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",                                                       Settings::Category::Overlay}; -    Settings::Setting<bool> show_thermal_overlay{linkage, false, "show_thermal_overlay", +    Settings::Setting<bool> show_thermal_overlay{linkage, true, "show_thermal_overlay",                                                   Settings::Category::Overlay}; +    Settings::Setting<bool> show_ram_overlay{linkage, true, "show_ram_overlay", +                                             Settings::Category::Overlay};      Settings::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",                                                 Settings::Category::Overlay};      Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay}; diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml index df91a08c5..fe028e028 100644 --- a/src/android/app/src/main/res/layout/fragment_emulation.xml +++ b/src/android/app/src/main/res/layout/fragment_emulation.xml @@ -171,6 +171,21 @@          </FrameLayout> +        <com.google.android.material.textview.MaterialTextView +            android:id="@+id/show_ram_text" +            style="@style/TextAppearance.Material3.BodySmall" +            android:layout_width="wrap_content" +            android:layout_height="wrap_content" +            android:layout_gravity="left" +            android:layout_marginTop="24dp" +            android:clickable="false" +            android:focusable="false" +            android:textColor="@android:color/white" +            android:shadowColor="@android:color/black" +            android:shadowRadius="3" +            android:layout_below="@id/show_fps_text" +            tools:ignore="RtlHardcoded" /> +      </androidx.coordinatorlayout.widget.CoordinatorLayout>      <com.google.android.material.navigation.NavigationView diff --git a/src/android/app/src/main/res/menu/menu_overlay_options.xml b/src/android/app/src/main/res/menu/menu_overlay_options.xml index a9e807427..d601421a7 100644 --- a/src/android/app/src/main/res/menu/menu_overlay_options.xml +++ b/src/android/app/src/main/res/menu/menu_overlay_options.xml @@ -12,6 +12,11 @@          android:checkable="true" />      <item +        android:id="@+id/ram_meter" +        android:title="@string/emulation_ram_meter" +        android:checkable="true" /> + +    <item          android:id="@+id/menu_edit_overlay"          android:title="@string/emulation_touch_overlay_edit" /> diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index 5133fa98e..ce2b21bf1 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -480,6 +480,7 @@      <string name="emulation_done">Done</string>      <string name="emulation_fps_counter">FPS counter</string>      <string name="emulation_thermal_indicator">Thermal indicator</string> +    <string name="emulation_ram_meter">RAM meter</string>      <string name="emulation_toggle_controls">Toggle controls</string>      <string name="emulation_rel_stick_center">Relative stick center</string>      <string name="emulation_dpad_slide">D-pad slide</string>  | 
