|
|
|
@ -7,6 +7,7 @@ import android.annotation.SuppressLint
|
|
|
|
|
import android.app.AlertDialog
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.content.DialogInterface
|
|
|
|
|
import android.content.Intent
|
|
|
|
|
import android.content.SharedPreferences
|
|
|
|
|
import android.content.pm.ActivityInfo
|
|
|
|
|
import android.content.res.Resources
|
|
|
|
@ -19,11 +20,14 @@ import android.util.TypedValue
|
|
|
|
|
import android.view.*
|
|
|
|
|
import android.widget.TextView
|
|
|
|
|
import androidx.activity.OnBackPressedCallback
|
|
|
|
|
import androidx.activity.result.ActivityResultLauncher
|
|
|
|
|
import androidx.activity.result.contract.ActivityResultContracts
|
|
|
|
|
import androidx.appcompat.widget.PopupMenu
|
|
|
|
|
import androidx.core.content.res.ResourcesCompat
|
|
|
|
|
import androidx.core.graphics.Insets
|
|
|
|
|
import androidx.core.view.ViewCompat
|
|
|
|
|
import androidx.core.view.WindowInsetsCompat
|
|
|
|
|
import androidx.core.view.isVisible
|
|
|
|
|
import androidx.core.view.updatePadding
|
|
|
|
|
import androidx.fragment.app.Fragment
|
|
|
|
|
import androidx.lifecycle.Lifecycle
|
|
|
|
@ -61,11 +65,30 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
|
|
|
|
|
val args by navArgs<EmulationFragmentArgs>()
|
|
|
|
|
|
|
|
|
|
private lateinit var onReturnFromSettings: ActivityResultLauncher<Intent>
|
|
|
|
|
|
|
|
|
|
override fun onAttach(context: Context) {
|
|
|
|
|
super.onAttach(context)
|
|
|
|
|
if (context is EmulationActivity) {
|
|
|
|
|
emulationActivity = context
|
|
|
|
|
NativeLibrary.setEmulationActivity(context)
|
|
|
|
|
|
|
|
|
|
onReturnFromSettings = context.activityResultRegistry.register(
|
|
|
|
|
"SettingsResult", ActivityResultContracts.StartActivityForResult()
|
|
|
|
|
) {
|
|
|
|
|
binding.surfaceEmulation.setAspectRatio(
|
|
|
|
|
when (IntSetting.RENDERER_ASPECT_RATIO.int) {
|
|
|
|
|
0 -> Rational(16, 9)
|
|
|
|
|
1 -> Rational(4, 3)
|
|
|
|
|
2 -> Rational(21, 9)
|
|
|
|
|
3 -> Rational(16, 10)
|
|
|
|
|
4 -> null // Stretch
|
|
|
|
|
else -> Rational(16, 9)
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
emulationActivity?.buildPictureInPictureParams()
|
|
|
|
|
updateScreenLayout()
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
|
|
|
|
|
}
|
|
|
|
@ -129,7 +152,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
R.id.menu_settings -> {
|
|
|
|
|
SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "")
|
|
|
|
|
SettingsActivity.launch(
|
|
|
|
|
requireContext(), onReturnFromSettings, SettingsFile.FILE_NAME_CONFIG, ""
|
|
|
|
|
)
|
|
|
|
|
true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -162,7 +187,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
|
|
|
|
|
WindowInfoTracker.getOrCreate(requireContext())
|
|
|
|
|
.windowLayoutInfo(requireActivity())
|
|
|
|
|
.collect { updateCurrentLayout(requireActivity() as EmulationActivity, it) }
|
|
|
|
|
.collect { updateFoldableLayout(requireActivity() as EmulationActivity, it) }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -204,6 +229,37 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
super.onDetach()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun isEmulationStatePaused() : Boolean {
|
|
|
|
|
return this::emulationState.isInitialized && emulationState.isPaused
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onPictureInPictureEnter() {
|
|
|
|
|
if (binding.drawerLayout.isOpen) {
|
|
|
|
|
binding.drawerLayout.close()
|
|
|
|
|
}
|
|
|
|
|
if (EmulationMenuSettings.showOverlay) {
|
|
|
|
|
binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = false }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onPictureInPicturePause() {
|
|
|
|
|
if (!emulationState.isPaused) {
|
|
|
|
|
emulationState.pause()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onPictureInPicturePlay() {
|
|
|
|
|
if (emulationState.isPaused) {
|
|
|
|
|
emulationState.run(false)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fun onPictureInPictureLeave() {
|
|
|
|
|
if (EmulationMenuSettings.showOverlay) {
|
|
|
|
|
binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = true }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private fun refreshInputOverlay() {
|
|
|
|
|
binding.surfaceInputOverlay.refreshControls()
|
|
|
|
|
}
|
|
|
|
@ -243,15 +299,33 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@SuppressLint("SourceLockedOrientationActivity")
|
|
|
|
|
private fun updateScreenLayout() {
|
|
|
|
|
emulationActivity?.let {
|
|
|
|
|
when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
|
|
|
|
|
Settings.LayoutOption_MobileLandscape -> {
|
|
|
|
|
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
|
|
|
|
}
|
|
|
|
|
Settings.LayoutOption_MobilePortrait -> {
|
|
|
|
|
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
|
|
|
|
|
}
|
|
|
|
|
Settings.LayoutOption_Default -> {
|
|
|
|
|
it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
|
|
|
}
|
|
|
|
|
else -> { it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE }
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
|
|
|
|
|
|
|
|
|
|
fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
|
|
|
|
|
fun updateFoldableLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
|
|
|
|
|
val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let {
|
|
|
|
|
if (it.isSeparating) {
|
|
|
|
|
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
|
|
|
if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
|
|
|
|
|
binding.surfaceEmulation.layoutParams.height = it.bounds.top
|
|
|
|
|
binding.inGameMenu.layoutParams.height = it.bounds.bottom
|
|
|
|
|
binding.emulationContainer.layoutParams.height = it.bounds.top
|
|
|
|
|
// Prevent touch regions from being displayed in the hinge
|
|
|
|
|
binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx
|
|
|
|
|
binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx)
|
|
|
|
|
}
|
|
|
|
@ -259,14 +333,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
|
|
|
|
it.isSeparating
|
|
|
|
|
} ?: false
|
|
|
|
|
if (!isFolding) {
|
|
|
|
|
binding.surfaceEmulation.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
|
|
|
binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
|
|
|
binding.emulationContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
|
|
|
binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
|
|
|
|
|
binding.overlayContainer.updatePadding(0, 0, 0, 0)
|
|
|
|
|
emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
|
|
|
|
updateScreenLayout()
|
|
|
|
|
}
|
|
|
|
|
binding.surfaceInputOverlay.requestLayout()
|
|
|
|
|
binding.inGameMenu.requestLayout()
|
|
|
|
|
binding.emulationContainer.requestLayout()
|
|
|
|
|
binding.overlayContainer.requestLayout()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|