mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-13 09:18:43 +07:00
Android: selectable orientation (#8822)
* Android: selectable orientation * Fix visible rectangle bug, fix auto-rotate behaviour, add translations * Fix translation --------- Co-authored-by: vegeta1k95 <vfylfhby>
This commit is contained in:
@ -1,39 +1,20 @@
|
||||
package com.unciv.app
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.graphics.Rect
|
||||
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 android.view.WindowManager
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.work.WorkManager
|
||||
import com.badlogic.gdx.Gdx
|
||||
import com.badlogic.gdx.backends.android.AndroidApplication
|
||||
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration
|
||||
import com.badlogic.gdx.backends.android.AndroidGraphics
|
||||
import com.badlogic.gdx.math.Rectangle
|
||||
import com.unciv.UncivGame
|
||||
import com.unciv.logic.files.UncivFiles
|
||||
import com.unciv.logic.event.EventBus
|
||||
import com.unciv.ui.components.Fonts
|
||||
import com.unciv.ui.screens.basescreen.UncivStage
|
||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||
import com.unciv.utils.Display
|
||||
import com.unciv.utils.Log
|
||||
import com.unciv.utils.concurrency.Concurrency
|
||||
import java.io.File
|
||||
|
||||
open class AndroidLauncher : AndroidApplication() {
|
||||
|
||||
private var game: AndroidGame? = null
|
||||
private var deepLinkedMultiplayerGame: String? = null
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -59,68 +40,15 @@ open class AndroidLauncher : AndroidApplication() {
|
||||
val config = AndroidApplicationConfiguration().apply { useImmersiveMode = true }
|
||||
val settings = UncivFiles.getSettingsForPlatformLaunchers(filesDir.path)
|
||||
|
||||
// Setup orientation lock and display cutout
|
||||
allowPortrait(settings.allowAndroidPortrait)
|
||||
setDisplayCutout(settings.androidCutout)
|
||||
// Setup orientation and display cutout
|
||||
Display.setOrientation(settings.displayOrientation)
|
||||
Display.setCutout(settings.androidCutout)
|
||||
|
||||
game = AndroidGame(this)
|
||||
game = AndroidGame()
|
||||
initialize(game, config)
|
||||
|
||||
setDeepLinkedGame(intent)
|
||||
|
||||
val glView = (Gdx.graphics as AndroidGraphics).view as GLSurfaceView
|
||||
|
||||
addScreenObscuredListener(glView)
|
||||
}
|
||||
|
||||
fun allowPortrait(allow: Boolean) {
|
||||
val orientation = when {
|
||||
allow -> ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
}
|
||||
// Comparison ensures ActivityTaskManager.getService().setRequestedOrientation isn't called unless necessary
|
||||
if (requestedOrientation != orientation) requestedOrientation = orientation
|
||||
}
|
||||
|
||||
private fun setDisplayCutout(cutout: Boolean) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) return
|
||||
window.attributes.layoutInDisplayCutoutMode = when {
|
||||
cutout -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
else -> WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
override fun onGlobalLayout() {
|
||||
if (!UncivGame.isCurrentInitialized() || UncivGame.Current.screen == null) {
|
||||
return
|
||||
}
|
||||
val r = Rect()
|
||||
surfaceView.getWindowVisibleDisplayFrame(r)
|
||||
if (r.equals(lastVisibleDisplayFrame)) return
|
||||
lastVisibleDisplayFrame = r
|
||||
|
||||
val stage = (UncivGame.Current.screen as BaseScreen).stage
|
||||
|
||||
val horizontalRatio = stage.width / surfaceView.width
|
||||
val verticalRatio = stage.height / surfaceView.height
|
||||
|
||||
val visibleStage = Rectangle(
|
||||
r.left * horizontalRatio,
|
||||
(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
|
||||
)
|
||||
Concurrency.runOnGLThread {
|
||||
EventBus.send(UncivStage.VisibleAreaChanged(visibleStage))
|
||||
}
|
||||
}
|
||||
})
|
||||
game!!.setDeepLinkedGame(intent)
|
||||
game!!.addScreenObscuredListener()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -141,34 +69,29 @@ open class AndroidLauncher : AndroidApplication() {
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
if (UncivGame.isCurrentInitialized()
|
||||
&& UncivGame.Current.gameInfo != null
|
||||
&& UncivGame.Current.settings.multiplayer.turnCheckerEnabled
|
||||
&& UncivGame.Current.files.getMultiplayerSaves().any()
|
||||
val game = this.game!!
|
||||
if (game.isInitialized
|
||||
&& game.gameInfo != null
|
||||
&& game.settings.multiplayer.turnCheckerEnabled
|
||||
&& game.files.getMultiplayerSaves().any()
|
||||
) {
|
||||
MultiplayerTurnCheckWorker.startTurnChecker(
|
||||
applicationContext, UncivGame.Current.files,
|
||||
UncivGame.Current.gameInfo!!, UncivGame.Current.settings.multiplayer
|
||||
)
|
||||
applicationContext, game.files, game.gameInfo!!, game.settings.multiplayer)
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
try { // Sometimes this fails for no apparent reason - the multiplayer checker failing to cancel should not be enough of a reason for the game to crash!
|
||||
try {
|
||||
WorkManager.getInstance(applicationContext).cancelAllWorkByTag(MultiplayerTurnCheckWorker.WORK_TAG)
|
||||
with(NotificationManagerCompat.from(this)) {
|
||||
cancel(MultiplayerTurnCheckWorker.NOTIFICATION_ID_INFO)
|
||||
cancel(MultiplayerTurnCheckWorker.NOTIFICATION_ID_SERVICE)
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
} catch (ignore: Exception) {
|
||||
/* Sometimes this fails for no apparent reason - the multiplayer checker failing to
|
||||
cancel should not be enough of a reason for the game to crash! */
|
||||
}
|
||||
|
||||
if (deepLinkedMultiplayerGame != null) {
|
||||
game?.deepLinkedMultiplayerGame = deepLinkedMultiplayerGame
|
||||
deepLinkedMultiplayerGame = null
|
||||
}
|
||||
|
||||
super.onResume()
|
||||
}
|
||||
|
||||
@ -176,17 +99,7 @@ open class AndroidLauncher : AndroidApplication() {
|
||||
super.onNewIntent(intent)
|
||||
if (intent == null)
|
||||
return
|
||||
|
||||
setDeepLinkedGame(intent)
|
||||
}
|
||||
|
||||
private fun setDeepLinkedGame(intent: Intent) {
|
||||
// This is needed in onCreate _and_ onNewIntent to open links and notifications
|
||||
// correctly even if the app was not running
|
||||
deepLinkedMultiplayerGame = if (intent.action != Intent.ACTION_VIEW) null else {
|
||||
val uri: Uri? = intent.data
|
||||
uri?.getQueryParameter("id")
|
||||
}
|
||||
game?.setDeepLinkedGame(intent)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
|
Reference in New Issue
Block a user