android: Add thermal throttling overlay
This commit is contained in:
parent
71e59bdcd8
commit
5fa9bc192c
6 changed files with 76 additions and 5 deletions
|
@ -25,7 +25,8 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||||
HAPTIC_FEEDBACK("haptic_feedback"),
|
HAPTIC_FEEDBACK("haptic_feedback"),
|
||||||
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
|
SHOW_PERFORMANCE_OVERLAY("show_performance_overlay"),
|
||||||
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
SHOW_INPUT_OVERLAY("show_input_overlay"),
|
||||||
TOUCHSCREEN("touchscreen");
|
TOUCHSCREEN("touchscreen"),
|
||||||
|
SHOW_THERMAL_OVERLAY("show_thermal_overlay");
|
||||||
|
|
||||||
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
override fun getBoolean(needsGlobal: Boolean): Boolean =
|
||||||
NativeConfig.getBoolean(key, needsGlobal)
|
NativeConfig.getBoolean(key, needsGlobal)
|
||||||
|
|
|
@ -13,6 +13,7 @@ import android.net.Uri
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
|
import android.os.PowerManager
|
||||||
import android.os.SystemClock
|
import android.os.SystemClock
|
||||||
import android.view.*
|
import android.view.*
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
|
@ -23,6 +24,7 @@ import androidx.core.content.res.ResourcesCompat
|
||||||
import androidx.core.graphics.Insets
|
import androidx.core.graphics.Insets
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
import androidx.drawerlayout.widget.DrawerLayout.DrawerListener
|
||||||
import androidx.fragment.app.Fragment
|
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.dialog.MaterialAlertDialogBuilder
|
||||||
import com.google.android.material.slider.Slider
|
import com.google.android.material.slider.Slider
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.collect
|
|
||||||
import kotlinx.coroutines.flow.collectLatest
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
import org.yuzu.yuzu_emu.HomeNavigationDirections
|
||||||
|
@ -64,6 +65,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
private lateinit var emulationState: EmulationState
|
private lateinit var emulationState: EmulationState
|
||||||
private var emulationActivity: EmulationActivity? = null
|
private var emulationActivity: EmulationActivity? = null
|
||||||
private var perfStatsUpdater: (() -> Unit)? = null
|
private var perfStatsUpdater: (() -> Unit)? = null
|
||||||
|
private var thermalStatsUpdater: (() -> Unit)? = null
|
||||||
|
|
||||||
private var _binding: FragmentEmulationBinding? = null
|
private var _binding: FragmentEmulationBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
|
@ -77,6 +79,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
private var isInFoldableLayout = false
|
private var isInFoldableLayout = false
|
||||||
|
|
||||||
|
private lateinit var powerManager: PowerManager
|
||||||
|
|
||||||
override fun onAttach(context: Context) {
|
override fun onAttach(context: Context) {
|
||||||
super.onAttach(context)
|
super.onAttach(context)
|
||||||
if (context is EmulationActivity) {
|
if (context is EmulationActivity) {
|
||||||
|
@ -102,6 +106,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
updateOrientation()
|
updateOrientation()
|
||||||
|
|
||||||
|
powerManager = requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||||
|
|
||||||
val intentUri: Uri? = requireActivity().intent.data
|
val intentUri: Uri? = requireActivity().intent.data
|
||||||
var intentGame: Game? = null
|
var intentGame: Game? = null
|
||||||
if (intentUri != null) {
|
if (intentUri != null) {
|
||||||
|
@ -394,8 +400,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
emulationState.updateSurface()
|
emulationState.updateSurface()
|
||||||
|
|
||||||
// Setup overlay
|
// Setup overlays
|
||||||
updateShowFpsOverlay()
|
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")
|
@SuppressLint("SourceLockedOrientationActivity")
|
||||||
private fun updateOrientation() {
|
private fun updateOrientation() {
|
||||||
emulationActivity?.let {
|
emulationActivity?.let {
|
||||||
|
@ -641,6 +680,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
popup.menu.apply {
|
popup.menu.apply {
|
||||||
findItem(R.id.menu_toggle_fps).isChecked =
|
findItem(R.id.menu_toggle_fps).isChecked =
|
||||||
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
|
BooleanSetting.SHOW_PERFORMANCE_OVERLAY.getBoolean()
|
||||||
|
findItem(R.id.thermal_indicator).isChecked =
|
||||||
|
BooleanSetting.SHOW_THERMAL_OVERLAY.getBoolean()
|
||||||
findItem(R.id.menu_rel_stick_center).isChecked =
|
findItem(R.id.menu_rel_stick_center).isChecked =
|
||||||
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
|
BooleanSetting.JOYSTICK_REL_CENTER.getBoolean()
|
||||||
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
findItem(R.id.menu_dpad_slide).isChecked = BooleanSetting.DPAD_SLIDE.getBoolean()
|
||||||
|
@ -660,6 +701,13 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
R.id.thermal_indicator -> {
|
||||||
|
it.isChecked = !it.isChecked
|
||||||
|
BooleanSetting.SHOW_THERMAL_OVERLAY.setBoolean(it.isChecked)
|
||||||
|
updateThermalOverlay()
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
R.id.menu_edit_overlay -> {
|
R.id.menu_edit_overlay -> {
|
||||||
binding.drawerLayout.close()
|
binding.drawerLayout.close()
|
||||||
binding.surfaceInputOverlay.requestFocus()
|
binding.surfaceInputOverlay.requestFocus()
|
||||||
|
@ -850,7 +898,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
right = cutInsets.right
|
right = cutInsets.right
|
||||||
}
|
}
|
||||||
|
|
||||||
v.setPadding(left, cutInsets.top, right, 0)
|
v.updatePadding(left = left, top = cutInsets.top, right = right)
|
||||||
windowInsets
|
windowInsets
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1003,5 +1051,6 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
||||||
|
private val thermalStatsUpdateHandler = Handler(Looper.myLooper()!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,8 @@ struct Values {
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
|
Settings::Setting<bool> show_performance_overlay{linkage, true, "show_performance_overlay",
|
||||||
Settings::Category::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::Setting<bool> show_input_overlay{linkage, true, "show_input_overlay",
|
||||||
Settings::Category::Overlay};
|
Settings::Category::Overlay};
|
||||||
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
Settings::Setting<bool> touchscreen{linkage, true, "touchscreen", Settings::Category::Overlay};
|
||||||
|
|
|
@ -140,6 +140,7 @@
|
||||||
android:id="@+id/overlay_container"
|
android:id="@+id/overlay_container"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginHorizontal="20dp"
|
||||||
android:fitsSystemWindows="true">
|
android:fitsSystemWindows="true">
|
||||||
|
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
|
@ -150,7 +151,19 @@
|
||||||
android:layout_gravity="left"
|
android:layout_gravity="left"
|
||||||
android:clickable="false"
|
android:clickable="false"
|
||||||
android:focusable="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:textColor="@android:color/white"
|
||||||
android:shadowColor="@android:color/black"
|
android:shadowColor="@android:color/black"
|
||||||
android:shadowRadius="3"
|
android:shadowRadius="3"
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
android:title="@string/emulation_fps_counter"
|
android:title="@string/emulation_fps_counter"
|
||||||
android:checkable="true" />
|
android:checkable="true" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/thermal_indicator"
|
||||||
|
android:title="@string/emulation_thermal_indicator"
|
||||||
|
android:checkable="true" />
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/menu_edit_overlay"
|
android:id="@+id/menu_edit_overlay"
|
||||||
android:title="@string/emulation_touch_overlay_edit" />
|
android:title="@string/emulation_touch_overlay_edit" />
|
||||||
|
|
|
@ -380,6 +380,7 @@
|
||||||
<string name="emulation_exit">Exit emulation</string>
|
<string name="emulation_exit">Exit emulation</string>
|
||||||
<string name="emulation_done">Done</string>
|
<string name="emulation_done">Done</string>
|
||||||
<string name="emulation_fps_counter">FPS counter</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_toggle_controls">Toggle controls</string>
|
||||||
<string name="emulation_rel_stick_center">Relative stick center</string>
|
<string name="emulation_rel_stick_center">Relative stick center</string>
|
||||||
<string name="emulation_dpad_slide">D-pad slide</string>
|
<string name="emulation_dpad_slide">D-pad slide</string>
|
||||||
|
|
Loading…
Reference in a new issue