Unciv/android/src/com/unciv/app/AndroidDisplay.kt
2024-06-29 23:57:11 +03:00

158 lines
5.8 KiB
Kotlin

package com.unciv.app
import android.content.pm.ActivityInfo
import android.os.Build
import android.view.Display
import android.view.Display.Mode
import android.view.View
import android.view.WindowManager
import androidx.annotation.RequiresApi
import com.badlogic.gdx.backends.android.AndroidApplication
import com.unciv.models.metadata.GameSettings
import com.unciv.models.translations.tr
import com.unciv.utils.PlatformDisplay
import com.unciv.utils.ScreenMode
import com.unciv.utils.ScreenOrientation
class AndroidDisplay(private val activity: AndroidApplication) : PlatformDisplay {
private var display: Display? = null
private var displayModes: HashMap<Int, ScreenMode> = hashMapOf()
init {
// Fetch current display
@Suppress("DEPRECATION") // M..P should use the deprecated API
display = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R -> activity.display
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> activity.windowManager.defaultDisplay
else -> null
}
// Add default mode
displayModes[AndroidScreenMode.defaultId] = AndroidScreenMode.default
// Add other supported modes
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
fetchScreenModes()
}
@RequiresApi(Build.VERSION_CODES.M)
private fun fetchScreenModes() {
val display = display ?: return
for (mode in display.supportedModes)
displayModes[mode.modeId] = AndroidScreenMode(mode)
}
override fun getScreenModes(): Map<Int, ScreenMode> {
return displayModes
}
override fun setScreenMode(id: Int, settings: GameSettings) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return
activity.runOnUiThread {
val params = activity.window.attributes
params.preferredDisplayModeId = id
activity.window.attributes = params
}
}
override fun hasSystemUiVisibility() = true
override fun setSystemUiVisibility(hide: Boolean) {
activity.runOnUiThread {
setSystemUiVisibilityFromUiThread(hide)
}
}
internal fun setSystemUiVisibilityFromUiThread(hide: Boolean) {
@Suppress("DEPRECATION") // Avoids @RequiresApi(Build.VERSION_CODES.R)
activity.window.decorView.systemUiVisibility =
if (hide)
View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
else
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
}
override fun hasCutout(): Boolean {
return when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.R ->
activity.display?.cutout != null
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ->
@Suppress("DEPRECATION")
activity.windowManager.defaultDisplay.cutout != null
Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ->
activity.window.decorView.rootWindowInsets.displayCutout != null
else -> false
}
}
override fun setCutout(enabled: Boolean) {
activity.runOnUiThread {
setCutoutFromUiThread(enabled)
}
}
internal fun setCutoutFromUiThread(enabled: Boolean) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return
val params = activity.window.attributes
params.layoutInDisplayCutoutMode = when {
enabled -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
}
activity.window.attributes = params // This is the only line to actually need to be running on the Ui Thread
}
/*
Sources for Info about current orientation in case need:
val windowManager = (activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager)
val displayRotation = windowManager.defaultDisplay.rotation
val currentOrientation = activity.resources.configuration.orientation
const val ORIENTATION_UNDEFINED = 0
const val ORIENTATION_PORTRAIT = 1
const val ORIENTATION_LANDSCAPE = 2
*/
override fun hasOrientation(): Boolean {
return true
}
override fun setOrientation(orientation: ScreenOrientation) {
val mode = when (orientation) {
// Automatically adjust landscape based on sensors.
ScreenOrientation.Landscape -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
// Automatically adjust the portrait based on the sensor.
ScreenOrientation.Portrait -> ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
ScreenOrientation.Auto -> ActivityInfo.SCREEN_ORIENTATION_SENSOR
}
// Ensure ActivityTaskManager.getService().setRequestedOrientation isn't called unless necessary!
if (activity.requestedOrientation != mode)
activity.requestedOrientation = mode
}
class AndroidScreenMode private constructor(
private val modeId: Int,
private val name: String
) : ScreenMode {
@RequiresApi(Build.VERSION_CODES.M)
constructor(mode: Mode) : this(mode.modeId, "${mode.physicalWidth}x${mode.physicalHeight} (${mode.refreshRate.toInt()}Hz)")
override fun getId(): Int {
return modeId
}
override fun toString(): String {
return name.tr()
}
companion object {
const val defaultId = 0
val default: AndroidScreenMode
get() = AndroidScreenMode(defaultId, "Default")
}
}
}