From 5537f6c60a72ec29fcb4a2781e039dff00a1fcae Mon Sep 17 00:00:00 2001 From: Kleidis Date: Mon, 1 Dec 2025 16:27:38 +0100 Subject: [PATCH] [android]: Force app to use the displays max set refresh rate Since Android 15, google automatically forces "games" to be 60 hrz. This ensures the display's max refresh rate is actually used. Tested on a Google Pixel 7 Pro with Android 16 Emulation Activity was excluded for battery usage concerns --- .../features/settings/ui/SettingsActivity.kt | 7 +++++ .../citra/citra_emu/ui/main/MainActivity.kt | 7 +++++ .../citra_emu/utils/SetMaxRefreshRate.kt | 26 +++++++++++++++++++ 3 files changed, 40 insertions(+) create mode 100644 src/android/app/src/main/java/org/citra/citra_emu/utils/SetMaxRefreshRate.kt diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt index 070a8f487..1ae915e5a 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/ui/SettingsActivity.kt @@ -7,6 +7,7 @@ package org.citra.citra_emu.features.settings.ui import android.content.Context import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.View import android.view.ViewGroup.MarginLayoutParams @@ -37,6 +38,7 @@ import org.citra.citra_emu.features.settings.utils.SettingsFile import org.citra.citra_emu.utils.SystemSaveGame import org.citra.citra_emu.utils.DirectoryInitialization import org.citra.citra_emu.utils.InsetsHelper +import org.citra.citra_emu.utils.MaxRefreshRate import org.citra.citra_emu.utils.ThemeUtil class SettingsActivity : AppCompatActivity(), SettingsActivityView { @@ -54,6 +56,11 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { super.onCreate(savedInstanceState) binding = ActivitySettingsBinding.inflate(layoutInflater) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + MaxRefreshRate.set(this) + } + setContentView(binding.root) WindowCompat.setDecorFitsSystemWindows(window, false) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt index 37bff3396..471a78cfa 100644 --- a/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/org/citra/citra_emu/ui/main/MainActivity.kt @@ -6,6 +6,7 @@ package org.citra.citra_emu.ui.main import android.content.Intent import android.net.Uri +import android.os.Build import android.os.Bundle import android.view.View import android.view.ViewGroup.MarginLayoutParams @@ -51,6 +52,7 @@ import org.citra.citra_emu.utils.CitraDirectoryUtils import org.citra.citra_emu.utils.DirectoryInitialization import org.citra.citra_emu.utils.FileBrowserHelper import org.citra.citra_emu.utils.InsetsHelper +import org.citra.citra_emu.utils.MaxRefreshRate import org.citra.citra_emu.utils.PermissionsHandler import org.citra.citra_emu.utils.ThemeUtil import org.citra.citra_emu.viewmodel.GamesViewModel @@ -86,6 +88,11 @@ class MainActivity : AppCompatActivity(), ThemeProvider { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + MaxRefreshRate.set(this) + } + setContentView(binding.root) WindowCompat.setDecorFitsSystemWindows(window, false) diff --git a/src/android/app/src/main/java/org/citra/citra_emu/utils/SetMaxRefreshRate.kt b/src/android/app/src/main/java/org/citra/citra_emu/utils/SetMaxRefreshRate.kt new file mode 100644 index 000000000..49a7ff15d --- /dev/null +++ b/src/android/app/src/main/java/org/citra/citra_emu/utils/SetMaxRefreshRate.kt @@ -0,0 +1,26 @@ +// Copyright Citra Emulator Project / Azahar Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +package org.citra.citra_emu.utils +import android.app.Activity +import android.os.Build +import androidx.annotation.RequiresApi + +object MaxRefreshRate { + @RequiresApi(Build.VERSION_CODES.R) + fun set(activity: Activity) { + val display = activity.display + val window = activity.window + display?.let { + val supportedModes = it.supportedModes + val maxRefreshRate = supportedModes.maxByOrNull { mode -> mode.refreshRate } + + if (maxRefreshRate != null) { + val layoutParams = window.attributes + layoutParams.preferredDisplayModeId = maxRefreshRate.modeId + window.attributes = layoutParams + } + } + } +} \ No newline at end of file