mirror of
https://github.com/geode-sdk/android-launcher.git
synced 2026-10-21 16:32:39 +00:00
Compare commits
7
Commits
1.9.0
...
latency-test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
df513983d1 | ||
|
|
a71071e3ac | ||
|
|
8578200db1 | ||
|
|
adb9dcc1e9 | ||
|
|
a32589b06c | ||
|
|
1773e54c84 | ||
|
|
5718b73470 |
No files matched your search
@@ -318,6 +318,7 @@ android {
|
||||
buildFeatures {
|
||||
compose = true
|
||||
buildConfig = true
|
||||
prefab = true
|
||||
}
|
||||
packaging {
|
||||
resources {
|
||||
@@ -359,6 +360,7 @@ dependencies {
|
||||
implementation ("androidx.activity:activity-ktx:1.13.0")
|
||||
implementation ("androidx.appcompat:appcompat:1.8.0")
|
||||
implementation ("androidx.documentfile:documentfile:1.1.0")
|
||||
implementation ("androidx.games:games-frame-pacing:2.1.3")
|
||||
|
||||
implementation ("com.squareup.okio:okio:3.18.2")
|
||||
implementation ("com.squareup.okhttp3:okhttp:5.5.0")
|
||||
|
||||
@@ -2,7 +2,9 @@ cmake_minimum_required(VERSION 3.21)
|
||||
|
||||
project(launcherfix)
|
||||
|
||||
add_library(launcherfix SHARED launcher-fix.cpp patcher.cpp)
|
||||
find_package(games-frame-pacing REQUIRED CONFIG)
|
||||
|
||||
add_library(launcherfix SHARED launcher-fix.cpp patcher.cpp pacing.cpp)
|
||||
|
||||
target_compile_features(launcherfix PUBLIC cxx_std_20)
|
||||
set_target_properties(launcherfix PROPERTIES CXX_EXTENSIONS OFF)
|
||||
@@ -14,4 +16,5 @@ set_target_properties(launcherfix PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
)
|
||||
|
||||
target_link_libraries(launcherfix PRIVATE log)
|
||||
target_link_libraries(launcherfix PRIVATE log android)
|
||||
target_link_libraries(launcherfix PRIVATE games-frame-pacing::swappy_static)
|
||||
@@ -0,0 +1,65 @@
|
||||
#include <swappy/swappyGL.h>
|
||||
#include <swappy/swappyGL_extra.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <memory>
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_initFramePacing(
|
||||
JNIEnv *env,
|
||||
jobject,
|
||||
jobject activity
|
||||
) {
|
||||
SwappyGL_init(env, activity);
|
||||
}
|
||||
|
||||
struct NativeWindowDeleter {
|
||||
void operator()(ANativeWindow* p) const {
|
||||
if (p != nullptr) ANativeWindow_release(p);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<ANativeWindow, NativeWindowDeleter> native_window = nullptr;
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_destroyFramePacing(JNIEnv*, jobject) {
|
||||
SwappyGL_destroy();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL Java_com_geode_launcher_LauncherFix_swapFrame(
|
||||
JNIEnv*,
|
||||
jobject,
|
||||
jlong display,
|
||||
jlong surface
|
||||
) {
|
||||
return SwappyGL_swap(
|
||||
reinterpret_cast<EGLDisplay>(display),
|
||||
reinterpret_cast<EGLSurface>(surface)
|
||||
);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setSurface(
|
||||
JNIEnv* env,
|
||||
jobject,
|
||||
jobject surface
|
||||
) {
|
||||
if (surface == nullptr) {
|
||||
native_window.reset();
|
||||
SwappyGL_setWindow(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
native_window.reset(ANativeWindow_fromSurface(env, surface));
|
||||
SwappyGL_setWindow(native_window.get());
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_com_geode_launcher_LauncherFix_setSwapInterval(
|
||||
JNIEnv* env,
|
||||
jobject,
|
||||
jlong interval_ns
|
||||
) {
|
||||
SwappyGL_setAutoSwapInterval(false);
|
||||
SwappyGL_setSwapIntervalNS(interval_ns);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -5,7 +5,9 @@ import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageInfo
|
||||
import android.opengl.GLSurfaceView
|
||||
import android.opengl.EGL14
|
||||
import android.opengl.EGLConfig
|
||||
import android.opengl.EGLDisplay
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
@@ -43,9 +45,6 @@ import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import javax.microedition.khronos.egl.EGL10
|
||||
import javax.microedition.khronos.egl.EGLConfig
|
||||
import javax.microedition.khronos.egl.EGLDisplay
|
||||
|
||||
enum class DisplayMode {
|
||||
DEFAULT, LIMITED, FULLSCREEN;
|
||||
@@ -78,6 +77,7 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
private var mAspectRatio = 0.0f
|
||||
private var mScreenZoom = 1.0f
|
||||
private var mScreenZoomFit = false
|
||||
private var mNativeFramePacing = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
setupUIState()
|
||||
@@ -131,6 +131,10 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
}
|
||||
})
|
||||
mGLSurfaceView?.manualBackEvents = true
|
||||
|
||||
if (mNativeFramePacing) {
|
||||
LauncherFix.initFramePacing(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createVersionFile() {
|
||||
@@ -491,9 +495,11 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
|
||||
val frameRate = mLimitedRefreshRate
|
||||
if (frameRate != null) {
|
||||
renderer.limitFrameRate(frameRate)
|
||||
glSurfaceView.setMaxFrameRate(frameRate)
|
||||
}
|
||||
|
||||
glSurfaceView.nativeFramePacing = mNativeFramePacing
|
||||
|
||||
editText.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS
|
||||
glSurfaceView.cocos2dxEditText = editText
|
||||
|
||||
@@ -529,6 +535,8 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
}
|
||||
}
|
||||
|
||||
mNativeFramePacing = preferenceUtils.getBoolean(PreferenceUtils.Key.NATIVE_FRAME_PACING)
|
||||
|
||||
if (displayMode == DisplayMode.FULLSCREEN && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
window.attributes.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
GeodeUtils.handleSafeArea = true
|
||||
@@ -562,6 +570,10 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
FMOD.close()
|
||||
|
||||
if (mNativeFramePacing) {
|
||||
LauncherFix.destroyFramePacing()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resumeGame() {
|
||||
@@ -733,11 +745,7 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
}
|
||||
}
|
||||
|
||||
class EGLConfigChooser : GLSurfaceView.EGLConfigChooser {
|
||||
// this comes from EGL14, but is unavailable on EGL10
|
||||
// also EGL14 is incompatible with EGL10. so whatever
|
||||
private var EGL_OPENGL_ES2_BIT: Int = 0x04
|
||||
|
||||
class EGLConfigChooser : ExplicitGLSurfaceView.EGLConfigChooser {
|
||||
private data class ConfigValues(
|
||||
val redSize: Int,
|
||||
val greenSize: Int,
|
||||
@@ -747,29 +755,29 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
val stencilSize: Int,
|
||||
)
|
||||
|
||||
private fun getAttribValue(egl: EGL10, display: EGLDisplay, config: EGLConfig, attrib: Int): Int {
|
||||
private fun getAttribValue(display: EGLDisplay, config: EGLConfig, attrib: Int): Int {
|
||||
val value = IntArray(1)
|
||||
egl.eglGetConfigAttrib(display, config, attrib, value)
|
||||
EGL14.eglGetConfigAttrib(display, config, attrib, value, 0)
|
||||
|
||||
return value[0]
|
||||
}
|
||||
|
||||
private fun testConfig(egl: EGL10, display: EGLDisplay, attrib: ConfigValues): EGLConfig? {
|
||||
private fun testConfig(display: EGLDisplay, attrib: ConfigValues): EGLConfig? {
|
||||
val attribList = intArrayOf(
|
||||
EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL10.EGL_RED_SIZE, attrib.redSize,
|
||||
EGL10.EGL_GREEN_SIZE, attrib.greenSize,
|
||||
EGL10.EGL_BLUE_SIZE, attrib.blueSize,
|
||||
EGL10.EGL_ALPHA_SIZE, attrib.alphaSize,
|
||||
EGL10.EGL_DEPTH_SIZE, attrib.depthSize,
|
||||
EGL10.EGL_STENCIL_SIZE, attrib.stencilSize,
|
||||
EGL10.EGL_NONE
|
||||
EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
|
||||
EGL14.EGL_RED_SIZE, attrib.redSize,
|
||||
EGL14.EGL_GREEN_SIZE, attrib.greenSize,
|
||||
EGL14.EGL_BLUE_SIZE, attrib.blueSize,
|
||||
EGL14.EGL_ALPHA_SIZE, attrib.alphaSize,
|
||||
EGL14.EGL_DEPTH_SIZE, attrib.depthSize,
|
||||
EGL14.EGL_STENCIL_SIZE, attrib.stencilSize,
|
||||
EGL14.EGL_NONE
|
||||
)
|
||||
|
||||
val configs = arrayOfNulls<EGLConfig>(1)
|
||||
val numConfigs = IntArray(1)
|
||||
|
||||
val res = egl.eglChooseConfig(display, attribList, configs, configs.size, numConfigs)
|
||||
val res = EGL14.eglChooseConfig(display, attribList, 0, configs, 0, configs.size, numConfigs, 0)
|
||||
if (res && numConfigs[0] > 0 && configs[0] != null) {
|
||||
return configs[0]
|
||||
}
|
||||
@@ -777,18 +785,18 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
return null
|
||||
}
|
||||
|
||||
private fun printConfig(egl: EGL10, display: EGLDisplay, config: EGLConfig) {
|
||||
val id = getAttribValue(egl, display, config, EGL10.EGL_CONFIG_ID)
|
||||
val red = getAttribValue(egl, display, config, EGL10.EGL_RED_SIZE)
|
||||
val green = getAttribValue(egl, display, config, EGL10.EGL_GREEN_SIZE)
|
||||
val blue = getAttribValue(egl, display, config, EGL10.EGL_BLUE_SIZE)
|
||||
val alpha = getAttribValue(egl, display, config, EGL10.EGL_ALPHA_SIZE)
|
||||
val depth = getAttribValue(egl, display, config, EGL10.EGL_DEPTH_SIZE)
|
||||
val stencil = getAttribValue(egl, display, config, EGL10.EGL_STENCIL_SIZE)
|
||||
private fun printConfig(display: EGLDisplay, config: EGLConfig) {
|
||||
val id = getAttribValue(display, config, EGL14.EGL_CONFIG_ID)
|
||||
val red = getAttribValue(display, config, EGL14.EGL_RED_SIZE)
|
||||
val green = getAttribValue(display, config, EGL14.EGL_GREEN_SIZE)
|
||||
val blue = getAttribValue(display, config, EGL14.EGL_BLUE_SIZE)
|
||||
val alpha = getAttribValue(display, config, EGL14.EGL_ALPHA_SIZE)
|
||||
val depth = getAttribValue(display, config, EGL14.EGL_DEPTH_SIZE)
|
||||
val stencil = getAttribValue(display, config, EGL14.EGL_STENCIL_SIZE)
|
||||
println("EGLConfig $id: (red = $red, green = $green, blue = $blue, alpha = $alpha, depth = $depth, stencil = $stencil)")
|
||||
}
|
||||
|
||||
override fun chooseConfig(egl: EGL10, display: EGLDisplay): EGLConfig {
|
||||
override fun chooseConfig(display: EGLDisplay): EGLConfig {
|
||||
val configs = listOf(
|
||||
ConfigValues(8, 8, 8, 8, 16, 8),
|
||||
ConfigValues(8, 8, 8, 0, 16, 8),
|
||||
@@ -797,9 +805,9 @@ class GeometryDashActivity : AppCompatActivity(), Cocos2dxHelper.Cocos2dxHelperL
|
||||
)
|
||||
|
||||
return configs.firstNotNullOf {
|
||||
val config = testConfig(egl, display, it)
|
||||
val config = testConfig(display, it)
|
||||
if (config != null) {
|
||||
printConfig(egl, display, config)
|
||||
printConfig(display, config)
|
||||
}
|
||||
|
||||
config
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.geode.launcher
|
||||
|
||||
import android.app.Activity
|
||||
import android.view.Surface
|
||||
import androidx.annotation.Keep
|
||||
import com.geode.launcher.utils.Constants
|
||||
|
||||
@@ -16,4 +18,10 @@ object LauncherFix {
|
||||
external fun enableExceptionsRenaming()
|
||||
|
||||
external fun performPatches()
|
||||
|
||||
external fun initFramePacing(activity: Activity)
|
||||
external fun destroyFramePacing()
|
||||
external fun swapFrame(display: Long, surface: Long): Boolean
|
||||
external fun setSurface(surface: Surface?)
|
||||
external fun setSwapInterval(intervalNs: Long)
|
||||
}
|
||||
@@ -169,6 +169,12 @@ fun DeveloperSettingsScreen(onBackPressedDispatcher: OnBackPressedDispatcher?) {
|
||||
}
|
||||
)
|
||||
|
||||
SettingsCard(
|
||||
title = stringResource(R.string.preference_native_pacing),
|
||||
description = stringResource(R.string.preference_native_pacing_description),
|
||||
preferenceKey = PreferenceUtils.Key.NATIVE_FRAME_PACING,
|
||||
)
|
||||
|
||||
/*
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
SettingsCard(
|
||||
|
||||
@@ -150,6 +150,7 @@ class PreferenceUtils(private val sharedPreferences: SharedPreferences) {
|
||||
LAST_LAUNCHER_UPDATE,
|
||||
DISABLE_UPDATE_CACHE,
|
||||
PREBUNDLED_GEODE_MIGRATION_PERFORMED,
|
||||
NATIVE_FRAME_PACING,
|
||||
}
|
||||
|
||||
private fun defaultValueForBooleanKey(key: Key): Boolean {
|
||||
@@ -201,6 +202,7 @@ class PreferenceUtils(private val sharedPreferences: SharedPreferences) {
|
||||
Key.LAST_LAUNCHER_UPDATE -> "PreferenceLastLauncherUpdate"
|
||||
Key.DISABLE_UPDATE_CACHE -> "PreferenceDisableUpdateCache"
|
||||
Key.PREBUNDLED_GEODE_MIGRATION_PERFORMED -> "PreferencePrebundledGeodeMigrationPerformed"
|
||||
Key.NATIVE_FRAME_PACING -> "PreferenceNativeFramePacing"
|
||||
// Key.RELEASE_CHANNEL -> "PreferenceReleaseChannel"
|
||||
// Key.LAST_DISMISSED_UPDATE -> "PreferenceLastDismissedUpdate"
|
||||
// Key.FORCE_HRR -> "PreferenceForceHighRefreshRate"
|
||||
|
||||
@@ -17,15 +17,18 @@ import android.view.inputmethod.InputMethodManager
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.widget.AppCompatEditText
|
||||
import com.customRobTop.BaseRobTopActivity
|
||||
import com.geode.launcher.ExplicitGLSurfaceView
|
||||
import com.geode.launcher.LauncherFix
|
||||
import com.geode.launcher.utils.GeodeUtils
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToLong
|
||||
|
||||
private const val HANDLER_OPEN_IME_KEYBOARD = 2
|
||||
private const val HANDLER_CLOSE_IME_KEYBOARD = 3
|
||||
private const val MS_TO_NS = 1_000_000
|
||||
private const val SEC_TO_NS = 1_000_000_000.0
|
||||
|
||||
class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
class Cocos2dxGLSurfaceView(context: Context) : ExplicitGLSurfaceView(context) {
|
||||
companion object {
|
||||
lateinit var cocos2dxGLSurfaceView: Cocos2dxGLSurfaceView
|
||||
private lateinit var handler: Handler
|
||||
@@ -64,6 +67,7 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
var controllerEventsEnabled = false
|
||||
private set
|
||||
var supportsResizeEvents = false
|
||||
var saveNativeFramePacing = false
|
||||
|
||||
var cocos2dxEditText: AppCompatEditText? = null
|
||||
set(value) {
|
||||
@@ -139,6 +143,10 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
|
||||
println("updateRefreshRate: selecting refresh rate of ${chosenDisplay.refreshRate} (display ${chosenDisplay.modeId})")
|
||||
|
||||
if (saveNativeFramePacing) {
|
||||
LauncherFix.setSwapInterval((1_000_000_000L / chosenRefreshRate).roundToLong())
|
||||
}
|
||||
|
||||
holder.surface.setFrameRate(chosenRefreshRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
|
||||
if (isAttachedToWindow) {
|
||||
(context as Activity).window.attributes.preferredRefreshRate = chosenRefreshRate
|
||||
@@ -153,6 +161,7 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
|
||||
renderMode = RENDERMODE_CONTINUOUSLY
|
||||
queueEvent { cocos2dxRenderer.handleOnResume() }
|
||||
}
|
||||
@@ -533,6 +542,11 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
setRenderer(this.cocos2dxRenderer)
|
||||
}
|
||||
|
||||
override fun setNativeFramePacing(nativeFramePacing: Boolean) {
|
||||
super.setNativeFramePacing(nativeFramePacing)
|
||||
saveNativeFramePacing = nativeFramePacing
|
||||
}
|
||||
|
||||
private fun getContentText(): String {
|
||||
return cocos2dxRenderer.getContentText()
|
||||
}
|
||||
@@ -567,6 +581,10 @@ class Cocos2dxGLSurfaceView(context: Context) : GLSurfaceView(context) {
|
||||
inputManager.unregisterInputDeviceListener(InputListener)
|
||||
}
|
||||
|
||||
fun setMaxFrameRate(rate: Int) {
|
||||
cocos2dxRenderer.limitFrameRate(rate)
|
||||
}
|
||||
|
||||
object InputListener : InputManager.InputDeviceListener {
|
||||
override fun onInputDeviceAdded(deviceId: Int) {
|
||||
GeodeUtils.inputDeviceAdded(deviceId)
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package org.cocos2dx.lib
|
||||
|
||||
import android.opengl.GLSurfaceView
|
||||
import android.opengl.EGLConfig
|
||||
import android.os.Build
|
||||
import javax.microedition.khronos.egl.EGLConfig
|
||||
import javax.microedition.khronos.opengles.GL10
|
||||
import com.geode.launcher.ExplicitGLSurfaceView
|
||||
|
||||
private const val NANOSECONDS_PER_SECOND = 1000000000L
|
||||
private const val NANOSECONDS_PER_MICROSECOND = 1000000L
|
||||
|
||||
@Suppress("unused", "KotlinJniMissingFunction")
|
||||
class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : GLSurfaceView.Renderer {
|
||||
class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : ExplicitGLSurfaceView.Renderer {
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun setAnimationInterval(@Suppress("UNUSED_PARAMETER") animationInterval: Double) {
|
||||
@@ -80,12 +79,12 @@ class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : GLSurfaceVi
|
||||
screenHeight = surfaceHeight
|
||||
}
|
||||
|
||||
override fun onSurfaceCreated(gl10: GL10?, eglConfig: EGLConfig?) {
|
||||
override fun onSurfaceCreated(eglConfig: EGLConfig?) {
|
||||
nativeInit(screenWidth, screenHeight)
|
||||
lastTickInNanoSeconds = System.nanoTime()
|
||||
}
|
||||
|
||||
override fun onSurfaceChanged(gl10: GL10?, width: Int, height: Int) {
|
||||
override fun onSurfaceChanged(width: Int, height: Int) {
|
||||
if (setFrameRate && Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
handler.updateRefreshRate()
|
||||
}
|
||||
@@ -93,7 +92,7 @@ class Cocos2dxRenderer(private var handler: Cocos2dxGLSurfaceView) : GLSurfaceVi
|
||||
println("renderer surfaceChanged: ${width}x${height}@${handler.display.refreshRate}fps")
|
||||
}
|
||||
|
||||
override fun onDrawFrame(gl: GL10?) {
|
||||
override fun onDrawFrame() {
|
||||
val animationInterval = mAnimationInterval
|
||||
if (animationInterval == null) {
|
||||
nativeRender()
|
||||
|
||||
@@ -298,6 +298,9 @@
|
||||
<string name="preference_profiles_delete_alt">Delete</string>
|
||||
<string name="preference_profiles_delete_undo_alt">Undo</string>
|
||||
|
||||
<string name="preference_native_pacing">Native frame pacing</string>
|
||||
<string name="preference_native_pacing_description">Reduces latency, but may worsen frame drops.</string>
|
||||
|
||||
<!-- ApplicationLogsActivity strings -->
|
||||
<string name="title_activity_application_logs">Application logs</string>
|
||||
<string name="application_logs_no_logs">No logs available.</string>
|
||||
|
||||
Reference in new issue
Block a user