Просмотр исходного кода

android: Add thermal throttling overlay

t895 2 лет назад
Родитель
Сommit
5fa9bc192c

+ 2 - 1
src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt

@@ -25,7 +25,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
     HAPTIC_FEEDBACK("haptic_feedback"),
     SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
     SHOW_INPUT_OVERLAY("show_input_overlay"),
-    TOUCHSCREEN("touchscreen");
+    TOUCHSCREEN("touchscreen"),
+    SHOW_THERMAL_OVERLAY("show_thermal_overlay");
 
     override fun getBoolean(needsGlobal: Boolean): Boolean =
         NativeConfig.getBoolean(key, needsGlobal)

+ 52 - 3
src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt

@@ -13,6 +13,7 @@ import android.net.Uri
 import android.os.Bundle
 import android.os.Handler
 import android.os.Looper
+import android.os.PowerManager
 import android.os.SystemClock
 import android.view.*
 import android.widget.TextView
@@ -23,6 +24,7 @@ import androidx.core.content.res.ResourcesCompat
 import androidx.core.graphics.Insets
 import androidx.core.view.ViewCompat
 import androidx.core.view.WindowInsetsCompat
+import androidx.core.view.updatePadding
 import androidx.drawerlayout.widget.DrawerLayout
 import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
 import androidx.fragment.app.Fragment
@@ -38,7 +40,6 @@ import androidx.window.layout.WindowLayoutInfo
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.google.android.material.slider.Slider
 import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.launch
 import org.yuzu.yuzu_emu.HomeNavigationDirections
@@ -64,6 +65,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     private lateinit var emulationState: EmulationState
     private var emulationActivity: EmulationActivity? = null
     private var perfStatsUpdater: (() -> Unit)? = null
+    private var thermalStatsUpdater: (() -> Unit)? = null
 
     private var _binding: FragmentEmulationBinding? = null
     private val binding get() = _binding!!
@@ -77,6 +79,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
 
     private var isInFoldableLayout = false
 
+    private lateinit var powerManager: PowerManager
+
     override fun onAttach(context: Context) {
         super.onAttach(context)
         if (context is EmulationActivity) {
@@ -102,6 +106,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         super.onCreate(savedInstanceState)
         updateOrientation()
 
+        powerManager = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
+
         val intentUri: Uri? = requireActivity().intent.data
         var intentGame: Game? = null
         if (intentUri != null) {
@@ -394,8 +400,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
 
                             emulationState.updateSurface()
 
-                            // Setup overlay
+                            // Setup overlays
                             updateShowFpsOverlay()
+                            updateThermalOverlay()
                         }
                     }
                 }
@@ -553,6 +560,38 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         }
     }
 
+    private fun updateThermalOverlay() {
+        if (BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()) {
+            thermalStatsUpdater = {
+                if (emulationViewModel.emulationStarted.value &&
+                    !emulationViewModel.isEmulationStopping.value
+                ) {
+                    val thermalStatus = when (powerManager.currentThermalStatus) {
+                        PowerManager.THERMAL_STATUS_LIGHT -> "😥"
+                        PowerManager.THERMAL_STATUS_MODERATE -> "🥵"
+                        PowerManager.THERMAL_STATUS_SEVERE -> "🔥"
+                        PowerManager.THERMAL_STATUS_CRITICAL,
+                        PowerManager.THERMAL_STATUS_EMERGENCY,
+                        PowerManager.THERMAL_STATUS_SHUTDOWN -> "☢️"
+
+                        else -> "🙂"
+                    }
+                    if (_binding != null) {
+                        binding.showThermalsText.text = thermalStatus
+                    }
+                    thermalStatsUpdateHandler.postDelayed(thermalStatsUpdater!!, 1000)
+                }
+            }
+            thermalStatsUpdateHandler.post(thermalStatsUpdater!!)
+            binding.showThermalsText.visibility = View.VISIBLE
+        } else {
+            if (thermalStatsUpdater != null) {
+                thermalStatsUpdateHandler.removeCallbacks(thermalStatsUpdater!!)
+            }
+            binding.showThermalsText.visibility = View.GONE
+        }
+    }
+
     @SuppressLint("SourceLockedOrientationActivity")
     private fun updateOrientation() {
         emulationActivity?.let {
@@ -641,6 +680,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         popup.menu.apply {
             findItem(R.id.menu_toggle_fps).isChecked =
                 BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
+            findItem(R.id.thermal_indicator).isChecked =
+                BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
             findItem(R.id.menu_rel_stick_center).isChecked =
                 BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
             findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
@@ -660,6 +701,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
                     true
                 }
 
+                R.id.thermal_indicator -> {
+                    it.isChecked = !it.isChecked
+                    BooleanSetting.SHOW_THERMAL_OVERLAY.setBoolean(it.isChecked)
+                    updateThermalOverlay()
+                    true
+                }
+
                 R.id.menu_edit_overlay -> {
                     binding.drawerLayout.close()
                     binding.surfaceInputOverlay.requestFocus()
@@ -850,7 +898,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
                 right = cutInsets.right
             }
 
-            v.setPadding(left, cutInsets.top, right, 0)
+            v.updatePadding(left = left, top = cutInsets.top, right = right)
             windowInsets
         }
     }
@@ -1003,5 +1051,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
 
     companion object {
         private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
+        private val thermalStatsUpdateHandler = Handler(Looper.myLooper()!!)
     }
 }

+ 2 - 0
src/android/app/src/main/jni/android_settings.h

@@ -60,6 +60,8 @@ 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::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};

+ 14 - 1
src/android/app/src/main/res/layout/fragment_emulation.xml

@@ -140,6 +140,7 @@
             android:id="@+id/overlay_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_marginHorizontal="20dp"
             android:fitsSystemWindows="true">
 
             <com.google.android.material.textview.MaterialTextView
@@ -150,7 +151,19 @@
                 android:layout_gravity="left"
                 android:clickable="false"
                 android:focusable="false"
-                android:paddingHorizontal="20dp"
+                android:textColor="@android:color/white"
+                android:shadowColor="@android:color/black"
+                android:shadowRadius="3"
+                tools:ignore="RtlHardcoded" />
+
+            <com.google.android.material.textview.MaterialTextView
+                android:id="@+id/show_thermals_text"
+                style="@style/TextAppearance.Material3.BodySmall"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="right"
+                android:clickable="false"
+                android:focusable="false"
                 android:textColor="@android:color/white"
                 android:shadowColor="@android:color/black"
                 android:shadowRadius="3"

+ 5 - 0
src/android/app/src/main/res/menu/menu_overlay_options.xml

@@ -6,6 +6,11 @@
         android:title="@string/emulation_fps_counter"
         android:checkable="true" />
 
+    <item
+        android:id="@+id/thermal_indicator"
+        android:title="@string/emulation_thermal_indicator"
+        android:checkable="true" />
+
     <item
         android:id="@+id/menu_edit_overlay"
         android:title="@string/emulation_touch_overlay_edit" />

+ 1 - 0
src/android/app/src/main/res/values/strings.xml

@@ -380,6 +380,7 @@
     <string name="emulation_exit">Exit emulation</string>
     <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_toggle_controls">Toggle controls</string>
     <string name="emulation_rel_stick_center">Relative stick center</string>
     <string name="emulation_dpad_slide">D-pad slide</string>