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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -2,10 +2,16 @@ package com.unciv.app
import android.content.Intent
import android.graphics.Rect
import android.hardware.display.DisplayManager
import android.net.Uri
import android.opengl.GLSurfaceView
import android.os.Build
import android.os.Bundle
import android.view.Surface
import android.view.SurfaceHolder
import android.view.View
import android.view.ViewTreeObserver
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationManagerCompat
import androidx.work.WorkManager
import com.badlogic.gdx.Gdx
@ -59,11 +65,39 @@ open class AndroidLauncher : AndroidApplication() {
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) {
contentView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
/** Request the best available device frame rate for
* 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.
* So we need to check if that was actually the thing that changed. */
private var lastVisibleDisplayFrame: Rect? = null
@ -73,18 +107,18 @@ open class AndroidLauncher : AndroidApplication() {
return
}
val r = Rect()
contentView.getWindowVisibleDisplayFrame(r)
surfaceView.getWindowVisibleDisplayFrame(r)
if (r.equals(lastVisibleDisplayFrame)) return
lastVisibleDisplayFrame = r
val stage = (UncivGame.Current.screen as BaseScreen).stage
val horizontalRatio = stage.width / contentView.width
val verticalRatio = stage.height / contentView.height
val horizontalRatio = stage.width / surfaceView.width
val verticalRatio = stage.height / surfaceView.height
val visibleStage = Rectangle(
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.height() * verticalRatio
)