From 060f7925603440f36e59ffbb355143be80f15add Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 9 Nov 2025 14:25:42 +0100 Subject: [PATCH] Android: Rate limit refreshInputOverlay calls from sliders Sliders can trigger change listeners very rapidly, so let's add some rate limiting so dragging a slider doesn't cause the whole UI to lag. (Now the input overlay looks laggy when dragging a slider, though.) --- .../activities/EmulationActivity.kt | 11 +++++-- .../dolphinemu/utils/RateLimiter.kt | 32 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/RateLimiter.kt diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt index 60d4311ee5d..1b23118de39 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.kt @@ -8,6 +8,8 @@ import android.graphics.Rect import android.net.Uri import android.os.Build import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.util.SparseIntArray import android.view.KeyEvent import android.view.MenuItem @@ -61,6 +63,7 @@ import org.dolphinemu.dolphinemu.ui.main.ThemeProvider import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner import org.dolphinemu.dolphinemu.utils.DirectoryInitialization import org.dolphinemu.dolphinemu.utils.FileBrowserHelper +import org.dolphinemu.dolphinemu.utils.RateLimiter import org.dolphinemu.dolphinemu.utils.ThemeHelper import kotlin.math.roundToInt @@ -88,6 +91,10 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { private lateinit var binding: ActivityEmulationBinding + private val refreshInputOverlayRateLimiter = RateLimiter(Handler(Looper.getMainLooper()), 100) { + emulationFragment?.refreshInputOverlay() + } + private val requestChangeDisc = registerForActivityResult( ActivityResultContracts.GetContent() ) { uri: Uri? -> @@ -729,7 +736,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { addOnChangeListener { _: Slider?, value: Float, _: Boolean -> dialogBinding.inputScaleValue.text = "${(value.toInt() + 50)}%" IntSetting.MAIN_CONTROL_SCALE.setInt(settings, value.toInt()) - emulationFragment?.refreshInputOverlay() + refreshInputOverlayRateLimiter.run() } } inputScaleValue.text = @@ -742,7 +749,7 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider { addOnChangeListener { _: Slider?, value: Float, _: Boolean -> inputOpacityValue.text = value.toInt().toString() + "%" IntSetting.MAIN_CONTROL_OPACITY.setInt(settings, value.toInt()) - emulationFragment?.refreshInputOverlay() + refreshInputOverlayRateLimiter.run() } } inputOpacityValue.text = inputOpacitySlider.value.toInt().toString() + "%" diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/RateLimiter.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/RateLimiter.kt new file mode 100644 index 00000000000..498e128875c --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/RateLimiter.kt @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +package org.dolphinemu.dolphinemu.utils + +import android.os.Handler +import android.os.SystemClock + +class RateLimiter( + private val handler: Handler, + private val delayBetweenRunsMs: Int, + private val runnable: Runnable +) { + private var nextAllowedRun = 0L + private var pendingRun = false + + fun run() { + if (!pendingRun) { + val time = SystemClock.uptimeMillis() + if (time >= nextAllowedRun) { + runnable.run() + nextAllowedRun = time + delayBetweenRunsMs + } else { + pendingRun = true + handler.postAtTime({ + runnable.run() + nextAllowedRun = SystemClock.uptimeMillis() + delayBetweenRunsMs + pendingRun = false + }, nextAllowedRun) + } + } + } +}