Android: use best possible device frame rate (#8728)

* Android: use best possible device frame rate

* Add support for devices with Android 6.0+

---------

Co-authored-by: vegeta1k95 <vfylfhby>
This commit is contained in:
vegeta1k95
2023-02-23 21:40:58 +01:00
committed by GitHub
parent 5d07fd981b
commit b5ce086860

View File

@ -2,10 +2,16 @@ package com.unciv.app
import android.content.Intent import android.content.Intent
import android.graphics.Rect import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.net.Uri import android.net.Uri
import android.opengl.GLSurfaceView
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Surface
import android.view.SurfaceHolder
import android.view.View import android.view.View
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.work.WorkManager import androidx.work.WorkManager
import com.badlogic.gdx.Gdx import com.badlogic.gdx.Gdx
@ -59,11 +65,39 @@ open class AndroidLauncher : AndroidApplication() {
setDeepLinkedGame(intent) setDeepLinkedGame(intent)
addScreenObscuredListener((Gdx.graphics as AndroidGraphics).view) val glView = (Gdx.graphics as AndroidGraphics).view as GLSurfaceView
addScreenObscuredListener(glView)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
addScreenRefreshRateListener(glView)
} }
private fun addScreenObscuredListener(contentView: View) { /** Request the best available device frame rate for
contentView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { * the game, as soon as OpenGL surface is created */
private fun addScreenRefreshRateListener(surfaceView: GLSurfaceView) {
surfaceView.holder.addCallback(object: SurfaceHolder.Callback {
override fun surfaceCreated(holder: SurfaceHolder) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val modes = display?.supportedModes ?: return
val bestRefreshRate = modes.maxOf { it.refreshRate }
holder.surface.setFrameRate(bestRefreshRate, Surface.FRAME_RATE_COMPATIBILITY_DEFAULT)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val display = windowManager.defaultDisplay
val modes = display?.supportedModes ?: return
val bestMode = modes.maxBy { it.refreshRate }
val params = window.attributes
params.preferredDisplayModeId = bestMode.modeId
window.attributes = params
}
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
override fun surfaceDestroyed(holder: SurfaceHolder) {}
})
}
private fun addScreenObscuredListener(surfaceView: GLSurfaceView) {
surfaceView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
/** [onGlobalLayout] gets triggered not only when the [windowVisibleDisplayFrame][View.getWindowVisibleDisplayFrame] changes, but also on other things. /** [onGlobalLayout] gets triggered not only when the [windowVisibleDisplayFrame][View.getWindowVisibleDisplayFrame] changes, but also on other things.
* So we need to check if that was actually the thing that changed. */ * So we need to check if that was actually the thing that changed. */
private var lastVisibleDisplayFrame: Rect? = null private var lastVisibleDisplayFrame: Rect? = null
@ -73,18 +107,18 @@ open class AndroidLauncher : AndroidApplication() {
return return
} }
val r = Rect() val r = Rect()
contentView.getWindowVisibleDisplayFrame(r) surfaceView.getWindowVisibleDisplayFrame(r)
if (r.equals(lastVisibleDisplayFrame)) return if (r.equals(lastVisibleDisplayFrame)) return
lastVisibleDisplayFrame = r lastVisibleDisplayFrame = r
val stage = (UncivGame.Current.screen as BaseScreen).stage val stage = (UncivGame.Current.screen as BaseScreen).stage
val horizontalRatio = stage.width / contentView.width val horizontalRatio = stage.width / surfaceView.width
val verticalRatio = stage.height / contentView.height val verticalRatio = stage.height / surfaceView.height
val visibleStage = Rectangle( val visibleStage = Rectangle(
r.left * horizontalRatio, r.left * horizontalRatio,
(contentView.height - r.bottom) * verticalRatio, // Android coordinate system has the origin in the top left, while GDX uses bottom left (surfaceView.height - r.bottom) * verticalRatio, // Android coordinate system has the origin in the top left, while GDX uses bottom left
r.width() * horizontalRatio, r.width() * horizontalRatio,
r.height() * verticalRatio r.height() * verticalRatio
) )