summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt61
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt33
-rw-r--r--src/android/app/src/main/res/layout/fragment_emulation.xml9
3 files changed, 75 insertions, 28 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
index 81474b824..901a3978d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt
@@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.activities
5 5
6import android.app.Activity 6import android.app.Activity
7import android.content.Context 7import android.content.Context
8import android.content.DialogInterface
9import android.content.Intent 8import android.content.Intent
10import android.content.res.Configuration 9import android.content.res.Configuration
11import android.graphics.Rect 10import android.graphics.Rect
@@ -13,22 +12,28 @@ import android.hardware.Sensor
13import android.hardware.SensorEvent 12import android.hardware.SensorEvent
14import android.hardware.SensorEventListener 13import android.hardware.SensorEventListener
15import android.hardware.SensorManager 14import android.hardware.SensorManager
15import android.hardware.display.DisplayManager
16import android.os.Bundle 16import android.os.Bundle
17import android.view.Display
17import android.view.InputDevice 18import android.view.InputDevice
18import android.view.KeyEvent 19import android.view.KeyEvent
19import android.view.MotionEvent 20import android.view.MotionEvent
20import android.view.Surface 21import android.view.Surface
21import android.view.View 22import android.view.View
22import android.view.WindowManager
23import android.view.inputmethod.InputMethodManager 23import android.view.inputmethod.InputMethodManager
24import androidx.appcompat.app.AppCompatActivity 24import androidx.appcompat.app.AppCompatActivity
25import androidx.preference.PreferenceManager 25import androidx.core.content.getSystemService
26import com.google.android.material.dialog.MaterialAlertDialogBuilder 26import androidx.core.view.WindowCompat
27import com.google.android.material.slider.Slider.OnChangeListener 27import androidx.core.view.WindowInsetsCompat
28import androidx.core.view.WindowInsetsControllerCompat
29import androidx.lifecycle.Lifecycle
30import androidx.lifecycle.lifecycleScope
31import androidx.lifecycle.repeatOnLifecycle
32import androidx.window.layout.WindowInfoTracker
33import kotlinx.coroutines.Dispatchers
34import kotlinx.coroutines.launch
28import org.yuzu.yuzu_emu.NativeLibrary 35import org.yuzu.yuzu_emu.NativeLibrary
29import org.yuzu.yuzu_emu.R 36import org.yuzu.yuzu_emu.R
30import org.yuzu.yuzu_emu.databinding.DialogSliderBinding
31import org.yuzu.yuzu_emu.features.settings.model.Settings
32import org.yuzu.yuzu_emu.fragments.EmulationFragment 37import org.yuzu.yuzu_emu.fragments.EmulationFragment
33import org.yuzu.yuzu_emu.model.Game 38import org.yuzu.yuzu_emu.model.Game
34import org.yuzu.yuzu_emu.utils.ControllerMappingHelper 39import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
@@ -44,7 +49,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
44 private var controllerMappingHelper: ControllerMappingHelper? = null 49 private var controllerMappingHelper: ControllerMappingHelper? = null
45 50
46 var isActivityRecreated = false 51 var isActivityRecreated = false
47 private var menuVisible = false
48 private var emulationFragment: EmulationFragment? = null 52 private var emulationFragment: EmulationFragment? = null
49 private lateinit var nfcReader: NfcReader 53 private lateinit var nfcReader: NfcReader
50 private lateinit var inputHandler: InputHandler 54 private lateinit var inputHandler: InputHandler
@@ -98,6 +102,14 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
98 inputHandler = InputHandler() 102 inputHandler = InputHandler()
99 inputHandler.initialize() 103 inputHandler.initialize()
100 104
105 lifecycleScope.launch(Dispatchers.Main) {
106 lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
107 WindowInfoTracker.getOrCreate(this@EmulationActivity)
108 .windowLayoutInfo(this@EmulationActivity)
109 .collect { emulationFragment?.updateCurrentLayout(this@EmulationActivity, it) }
110 }
111 }
112
101 // Start a foreground service to prevent the app from getting killed in the background 113 // Start a foreground service to prevent the app from getting killed in the background
102 val startIntent = Intent(this, ForegroundService::class.java) 114 val startIntent = Intent(this, ForegroundService::class.java)
103 startForegroundService(startIntent) 115 startForegroundService(startIntent)
@@ -241,20 +253,20 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
241 override fun onAccuracyChanged(sensor: Sensor, i: Int) {} 253 override fun onAccuracyChanged(sensor: Sensor, i: Int) {}
242 254
243 private fun getAdjustedRotation():Int { 255 private fun getAdjustedRotation():Int {
244 val rotation = windowManager.defaultDisplay.rotation; 256 val rotation = getSystemService<DisplayManager>()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation
245 val config: Configuration = resources.configuration 257 val config: Configuration = resources.configuration
246 258
247 if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 || 259 if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 ||
248 (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) { 260 (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) {
249 return rotation; 261 return rotation
250 } 262 }
251 when (rotation) { 263 when (rotation) {
252 Surface.ROTATION_0 -> return Surface.ROTATION_90; 264 Surface.ROTATION_0 -> return Surface.ROTATION_90
253 Surface.ROTATION_90 -> return Surface.ROTATION_0; 265 Surface.ROTATION_90 -> return Surface.ROTATION_0
254 Surface.ROTATION_180 -> return Surface.ROTATION_270; 266 Surface.ROTATION_180 -> return Surface.ROTATION_270
255 Surface.ROTATION_270 -> return Surface.ROTATION_180; 267 Surface.ROTATION_270 -> return Surface.ROTATION_180
256 } 268 }
257 return rotation; 269 return rotation
258 } 270 }
259 271
260 private fun restoreState(savedInstanceState: Bundle) { 272 private fun restoreState(savedInstanceState: Bundle) {
@@ -262,18 +274,13 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
262 } 274 }
263 275
264 private fun enableFullscreenImmersive() { 276 private fun enableFullscreenImmersive() {
265 window.attributes.layoutInDisplayCutoutMode = 277 WindowCompat.setDecorFitsSystemWindows(window, false)
266 WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES 278
267 279 WindowInsetsControllerCompat(window, window.decorView).let { controller ->
268 window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN) 280 controller.hide(WindowInsetsCompat.Type.systemBars())
269 281 controller.systemBarsBehavior =
270 // It would be nice to use IMMERSIVE_STICKY, but that doesn't show the toolbar. 282 WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
271 window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or 283 }
272 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
273 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
274 View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
275 View.SYSTEM_UI_FLAG_FULLSCREEN or
276 View.SYSTEM_UI_FLAG_IMMERSIVE
277 } 284 }
278 285
279 private fun startMotionSensorListener() { 286 private fun startMotionSensorListener() {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
index e00f02f86..1a9843fcc 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -8,10 +8,13 @@ import android.app.AlertDialog
8import android.content.Context 8import android.content.Context
9import android.content.DialogInterface 9import android.content.DialogInterface
10import android.content.SharedPreferences 10import android.content.SharedPreferences
11import android.content.pm.ActivityInfo
12import android.content.res.Resources
11import android.graphics.Color 13import android.graphics.Color
12import android.os.Bundle 14import android.os.Bundle
13import android.os.Handler 15import android.os.Handler
14import android.os.Looper 16import android.os.Looper
17import android.util.TypedValue
15import android.view.* 18import android.view.*
16import android.widget.TextView 19import android.widget.TextView
17import androidx.activity.OnBackPressedCallback 20import androidx.activity.OnBackPressedCallback
@@ -20,8 +23,11 @@ import androidx.core.content.res.ResourcesCompat
20import androidx.core.graphics.Insets 23import androidx.core.graphics.Insets
21import androidx.core.view.ViewCompat 24import androidx.core.view.ViewCompat
22import androidx.core.view.WindowInsetsCompat 25import androidx.core.view.WindowInsetsCompat
26import androidx.core.view.updatePadding
23import androidx.fragment.app.Fragment 27import androidx.fragment.app.Fragment
24import androidx.preference.PreferenceManager 28import androidx.preference.PreferenceManager
29import androidx.window.layout.FoldingFeature
30import androidx.window.layout.WindowLayoutInfo
25import com.google.android.material.dialog.MaterialAlertDialogBuilder 31import com.google.android.material.dialog.MaterialAlertDialogBuilder
26import com.google.android.material.slider.Slider 32import com.google.android.material.slider.Slider
27import org.yuzu.yuzu_emu.NativeLibrary 33import org.yuzu.yuzu_emu.NativeLibrary
@@ -211,6 +217,33 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
211 } 217 }
212 } 218 }
213 219
220 private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
221
222 fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
223 val isFolding = (newLayoutInfo.displayFeatures.find { it is FoldingFeature } as? FoldingFeature)?.let {
224 if (it.isSeparating) {
225 emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
226 if (it.orientation == FoldingFeature.Orientation.HORIZONTAL) {
227 binding.surfaceEmulation.layoutParams.height = it.bounds.top
228 binding.inGameMenu.layoutParams.height = it.bounds.bottom
229 binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx
230 binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx)
231 }
232 }
233 it.isSeparating
234 } ?: false
235 if (!isFolding) {
236 binding.surfaceEmulation.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
237 binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
238 binding.overlayContainer.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
239 binding.overlayContainer.updatePadding(0, 0, 0, 0)
240 emulationActivity.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
241 }
242 binding.surfaceInputOverlay.requestLayout()
243 binding.inGameMenu.requestLayout()
244 binding.overlayContainer.requestLayout()
245 }
246
214 override fun surfaceCreated(holder: SurfaceHolder) { 247 override fun surfaceCreated(holder: SurfaceHolder) {
215 // We purposely don't do anything here. 248 // We purposely don't do anything here.
216 // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation. 249 // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
diff --git a/src/android/app/src/main/res/layout/fragment_emulation.xml b/src/android/app/src/main/res/layout/fragment_emulation.xml
index 74ec512af..940dbd4bf 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -20,6 +20,12 @@
20 android:focusable="false" 20 android:focusable="false"
21 android:focusableInTouchMode="false" /> 21 android:focusableInTouchMode="false" />
22 22
23 <FrameLayout
24 android:id="@+id/overlay_container"
25 android:layout_width="match_parent"
26 android:layout_height="match_parent"
27 android:layout_gravity="bottom">
28
23 <!-- This is the onscreen input overlay --> 29 <!-- This is the onscreen input overlay -->
24 <org.yuzu.yuzu_emu.overlay.InputOverlay 30 <org.yuzu.yuzu_emu.overlay.InputOverlay
25 android:id="@+id/surface_input_overlay" 31 android:id="@+id/surface_input_overlay"
@@ -48,6 +54,7 @@
48 android:layout_gravity="center" 54 android:layout_gravity="center"
49 android:text="@string/emulation_done" 55 android:text="@string/emulation_done"
50 android:visibility="gone" /> 56 android:visibility="gone" />
57 </FrameLayout>
51 58
52 </androidx.coordinatorlayout.widget.CoordinatorLayout> 59 </androidx.coordinatorlayout.widget.CoordinatorLayout>
53 60
@@ -55,7 +62,7 @@
55 android:id="@+id/in_game_menu" 62 android:id="@+id/in_game_menu"
56 android:layout_width="wrap_content" 63 android:layout_width="wrap_content"
57 android:layout_height="match_parent" 64 android:layout_height="match_parent"
58 android:layout_gravity="start" 65 android:layout_gravity="start|bottom"
59 app:headerLayout="@layout/header_in_game" 66 app:headerLayout="@layout/header_in_game"
60 app:menu="@menu/menu_in_game" /> 67 app:menu="@menu/menu_in_game" />
61 68