diff --git a/.gitignore b/.gitignore
index a5f7248c7..fbadb208b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,6 +26,8 @@ CMakeSettings.json
 # OSX global filetypes
 # Created by Finder or Spotlight in directories for various OS functionality (indexing, etc)
 .DS_Store
+.DS_Store?
+._*
 .AppleDouble
 .LSOverride
 .Spotlight-V100
diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml
index b474ddb0b..a6f87fc2e 100644
--- a/src/android/app/src/main/AndroidManifest.xml
+++ b/src/android/app/src/main/AndroidManifest.xml
@@ -53,7 +53,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
         <activity
             android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"
             android:theme="@style/Theme.Yuzu.Main"
-            android:screenOrientation="userLandscape"
+            android:supportsPictureInPicture="true"
+            android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|uiMode"
             android:exported="true">
 
             <intent-filter>
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
index 4be9ade14..22f0a2646 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt
@@ -282,6 +282,11 @@ object NativeLibrary {
      */
     external fun isRunning(): Boolean
 
+    /**
+     * Returns true if emulation is paused.
+     */
+    external fun isPaused(): Boolean
+
     /**
      * Returns the performance stats for the current game
      */
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 caf660348..5ca519f0a 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
@@ -4,14 +4,23 @@
 package org.yuzu.yuzu_emu.activities
 
 import android.app.Activity
+import android.app.PendingIntent
+import android.app.PictureInPictureParams
+import android.app.RemoteAction
+import android.content.BroadcastReceiver
 import android.content.Context
 import android.content.Intent
+import android.content.IntentFilter
+import android.content.res.Configuration
 import android.graphics.Rect
+import android.graphics.drawable.Icon
 import android.hardware.Sensor
 import android.hardware.SensorEvent
 import android.hardware.SensorEventListener
 import android.hardware.SensorManager
+import android.os.Build
 import android.os.Bundle
+import android.util.Rational
 import android.view.InputDevice
 import android.view.KeyEvent
 import android.view.MotionEvent
@@ -27,6 +36,8 @@ import androidx.navigation.fragment.NavHostFragment
 import org.yuzu.yuzu_emu.NativeLibrary
 import org.yuzu.yuzu_emu.R
 import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding
+import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting
+import org.yuzu.yuzu_emu.features.settings.model.IntSetting
 import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel
 import org.yuzu.yuzu_emu.model.Game
 import org.yuzu.yuzu_emu.utils.ControllerMappingHelper
@@ -50,6 +61,9 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
     private var motionTimestamp: Long = 0
     private var flipMotionOrientation: Boolean = false
 
+    private val actionPause = "ACTION_EMULATOR_PAUSE"
+    private val actionPlay = "ACTION_EMULATOR_PLAY"
+
     private val settingsViewModel: SettingsViewModel by viewModels()
 
     override fun onDestroy() {
@@ -120,6 +134,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
         super.onResume()
         nfcReader.startScanning()
         startMotionSensorListener()
+
+        buildPictureInPictureParams()
     }
 
     override fun onPause() {
@@ -128,6 +144,16 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
         stopMotionSensorListener()
     }
 
+    override fun onUserLeaveHint() {
+        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
+            if (BooleanSetting.PICTURE_IN_PICTURE.boolean && !isInPictureInPictureMode) {
+                val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
+                    .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
+                enterPictureInPictureMode(pictureInPictureParamsBuilder.build())
+            }
+        }
+    }
+
     override fun onNewIntent(intent: Intent) {
         super.onNewIntent(intent)
         setIntent(intent)
@@ -230,6 +256,96 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
         }
     }
 
+    private fun PictureInPictureParams.Builder.getPictureInPictureAspectBuilder(): PictureInPictureParams.Builder {
+        val aspectRatio = when (IntSetting.RENDERER_ASPECT_RATIO.int) {
+            0 -> Rational(16, 9)
+            1 -> Rational(4, 3)
+            2 -> Rational(21, 9)
+            3 -> Rational(16, 10)
+            else -> null // Best fit
+        }
+        return this.apply { aspectRatio?.let { setAspectRatio(it) } }
+    }
+
+    private fun PictureInPictureParams.Builder.getPictureInPictureActionsBuilder(): PictureInPictureParams.Builder {
+        val pictureInPictureActions: MutableList<RemoteAction> = mutableListOf()
+        val pendingFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+
+        if (NativeLibrary.isPaused()) {
+            val playIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_play)
+            val playPendingIntent = PendingIntent.getBroadcast(
+                this@EmulationActivity,
+                R.drawable.ic_pip_play,
+                Intent(actionPlay),
+                pendingFlags
+            )
+            val playRemoteAction = RemoteAction(
+                playIcon,
+                getString(R.string.play),
+                getString(R.string.play),
+                playPendingIntent
+            )
+            pictureInPictureActions.add(playRemoteAction)
+        } else {
+            val pauseIcon = Icon.createWithResource(this@EmulationActivity, R.drawable.ic_pip_pause)
+            val pausePendingIntent = PendingIntent.getBroadcast(
+                this@EmulationActivity,
+                R.drawable.ic_pip_pause,
+                Intent(actionPause),
+                pendingFlags
+            )
+            val pauseRemoteAction = RemoteAction(
+                pauseIcon,
+                getString(R.string.pause),
+                getString(R.string.pause),
+                pausePendingIntent
+            )
+            pictureInPictureActions.add(pauseRemoteAction)
+        }
+
+        return this.apply { setActions(pictureInPictureActions) }
+    }
+
+    fun buildPictureInPictureParams() {
+        val pictureInPictureParamsBuilder = PictureInPictureParams.Builder()
+            .getPictureInPictureActionsBuilder().getPictureInPictureAspectBuilder()
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+            pictureInPictureParamsBuilder.setAutoEnterEnabled(BooleanSetting.PICTURE_IN_PICTURE.boolean)
+        }
+        setPictureInPictureParams(pictureInPictureParamsBuilder.build())
+    }
+
+    private var pictureInPictureReceiver = object : BroadcastReceiver() {
+        override fun onReceive(context: Context?, intent: Intent) {
+            if (intent.action == actionPlay) {
+                if (NativeLibrary.isPaused()) NativeLibrary.unPauseEmulation()
+            } else if (intent.action == actionPause) {
+                if (!NativeLibrary.isPaused()) NativeLibrary.pauseEmulation()
+            }
+            buildPictureInPictureParams()
+        }
+    }
+
+    override fun onPictureInPictureModeChanged(
+        isInPictureInPictureMode: Boolean,
+        newConfig: Configuration
+    ) {
+        super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
+        if (isInPictureInPictureMode) {
+            IntentFilter().apply {
+                addAction(actionPause)
+                addAction(actionPlay)
+            }.also {
+                registerReceiver(pictureInPictureReceiver, it)
+            }
+        } else {
+            try {
+                unregisterReceiver(pictureInPictureReceiver)
+            } catch (ignored : Exception) {
+            }
+        }
+    }
+
     private fun startMotionSensorListener() {
         val sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager
         val gyroSensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
index 3dfd66779..63b4df273 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt
@@ -8,6 +8,7 @@ enum class BooleanSetting(
     override val section: String,
     override val defaultValue: Boolean
 ) : AbstractBooleanSetting {
+    PICTURE_IN_PICTURE("picture_in_picture", Settings.SECTION_GENERAL, true),
     USE_CUSTOM_RTC("custom_rtc_enabled", Settings.SECTION_SYSTEM, false);
 
     override var boolean: Boolean = defaultValue
@@ -27,6 +28,7 @@ enum class BooleanSetting(
 
     companion object {
         private val NOT_RUNTIME_EDITABLE = listOf(
+            PICTURE_IN_PICTURE,
             USE_CUSTOM_RTC
         )
 
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
index fa84f94f5..4427a7d9d 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt
@@ -93,6 +93,11 @@ enum class IntSetting(
         Settings.SECTION_RENDERER,
         0
     ),
+    RENDERER_SCREEN_LAYOUT(
+        "screen_layout",
+        Settings.SECTION_RENDERER,
+        Settings.LayoutOption_MobileLandscape
+    ),
     RENDERER_ASPECT_RATIO(
         "aspect_ratio",
         Settings.SECTION_RENDERER,
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
index 8df20b928..6bcb7bee0 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt
@@ -133,7 +133,6 @@ class Settings {
         const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter"
         const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable"
         const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics"
-        const val PREF_MENU_SETTINGS_LANDSCAPE = "EmulationMenuSettings_LandscapeScreenLayout"
         const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps"
         const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay"
 
@@ -144,6 +143,10 @@ class Settings {
 
         private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap()
 
+        const val LayoutOption_Unspecified = 0
+        const val LayoutOption_MobilePortrait = 4
+        const val LayoutOption_MobileLandscape = 5
+
         init {
             configFileSectionsMap[SettingsFile.FILE_NAME_CONFIG] =
                 listOf(
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
index 72e2cce2a..da7062b87 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt
@@ -16,6 +16,7 @@ import androidx.core.view.WindowCompat
 import androidx.core.view.WindowInsetsCompat
 import android.view.ViewGroup.MarginLayoutParams
 import androidx.activity.OnBackPressedCallback
+import androidx.activity.result.ActivityResultLauncher
 import androidx.core.view.updatePadding
 import com.google.android.material.color.MaterialColors
 import org.yuzu.yuzu_emu.NativeLibrary
@@ -239,5 +240,17 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
             settings.putExtra(ARG_GAME_ID, gameId)
             context.startActivity(settings)
         }
+
+        fun launch(
+            context: Context,
+            launcher: ActivityResultLauncher<Intent>,
+            menuTag: String?,
+            gameId: String?
+        ) {
+            val settings = Intent(context, SettingsActivity::class.java)
+            settings.putExtra(ARG_MENU_TAG, menuTag)
+            settings.putExtra(ARG_GAME_ID, gameId)
+            launcher.launch(settings)
+        }
     }
 }
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
index 1ceaa6fb4..b611389a1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt
@@ -166,6 +166,15 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
                     IntSetting.CPU_ACCURACY.defaultValue
                 )
             )
+            add(
+                SwitchSetting(
+                    BooleanSetting.PICTURE_IN_PICTURE,
+                    R.string.picture_in_picture,
+                    R.string.picture_in_picture_description,
+                    BooleanSetting.PICTURE_IN_PICTURE.key,
+                    BooleanSetting.PICTURE_IN_PICTURE.defaultValue
+                )
+            )
         }
     }
 
@@ -283,6 +292,17 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
                     IntSetting.RENDERER_ANTI_ALIASING.defaultValue
                 )
             )
+            add(
+                SingleChoiceSetting(
+                    IntSetting.RENDERER_SCREEN_LAYOUT,
+                    R.string.renderer_screen_layout,
+                    0,
+                    R.array.rendererScreenLayoutNames,
+                    R.array.rendererScreenLayoutValues,
+                    IntSetting.RENDERER_SCREEN_LAYOUT.key,
+                    IntSetting.RENDERER_SCREEN_LAYOUT.defaultValue
+                )
+            )
             add(
                 SingleChoiceSetting(
                     IntSetting.RENDERER_ASPECT_RATIO,
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 02bfcdb1e..4b2305892 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
@@ -7,24 +7,26 @@ 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
+import android.content.res.Configuration
 import android.graphics.Color
 import android.os.Bundle
 import android.os.Handler
 import android.os.Looper
 import android.util.Rational
-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.updatePadding
+import androidx.core.view.isVisible
 import androidx.fragment.app.Fragment
 import androidx.lifecycle.Lifecycle
 import androidx.lifecycle.lifecycleScope
@@ -48,6 +50,7 @@ import org.yuzu.yuzu_emu.features.settings.model.IntSetting
 import org.yuzu.yuzu_emu.features.settings.model.Settings
 import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity
 import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile
+import org.yuzu.yuzu_emu.overlay.InputOverlay
 import org.yuzu.yuzu_emu.utils.*
 
 class EmulationFragment : Fragment(), SurfaceHolder.Callback {
@@ -61,11 +64,40 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
 
     val args by navArgs<EmulationFragmentArgs>()
 
+    private var isInFoldableLayout = false
+
+    private lateinit var onReturnFromSettings: ActivityResultLauncher<Intent>
+
     override fun onAttach(context: Context) {
         super.onAttach(context)
         if (context is EmulationActivity) {
             emulationActivity = context
             NativeLibrary.setEmulationActivity(context)
+
+            lifecycleScope.launch(Dispatchers.Main) {
+                lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
+                    WindowInfoTracker.getOrCreate(context)
+                        .windowLayoutInfo(context)
+                        .collect { updateFoldableLayout(context, it) }
+                }
+            }
+
+            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 +161,12 @@ 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 +199,33 @@ 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) }
+            }
+        }
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        if (emulationActivity?.isInPictureInPictureMode == true) {
+            if (binding.drawerLayout.isOpen) {
+                binding.drawerLayout.close()
+            }
+            if (EmulationMenuSettings.showOverlay) {
+                binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = false }
+            }
+        } else {
+            if (EmulationMenuSettings.showOverlay) {
+                binding.surfaceInputOverlay.post { binding.surfaceInputOverlay.isVisible = true }
+            }
+            if (!isInFoldableLayout) {
+                if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                    binding.surfaceInputOverlay.orientation = InputOverlay.PORTRAIT
+                } else {
+                    binding.surfaceInputOverlay.orientation = InputOverlay.LANDSCAPE
+                }
+            }
+            if (!binding.surfaceInputOverlay.isInEditMode) {
+                refreshInputOverlay()
             }
         }
     }
@@ -184,6 +247,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
             }
         )
 
+        updateScreenLayout()
+
         emulationState.run(emulationActivity!!.isActivityRecreated)
     }
 
@@ -243,31 +308,50 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         }
     }
 
-    private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt()
+    @SuppressLint("SourceLockedOrientationActivity")
+    private fun updateScreenLayout() {
+        emulationActivity?.let {
+            it.requestedOrientation = when (IntSetting.RENDERER_SCREEN_LAYOUT.int) {
+                Settings.LayoutOption_MobileLandscape -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
+                Settings.LayoutOption_MobilePortrait -> ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
+                Settings.LayoutOption_Unspecified -> ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+                else -> ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
+            }
+        }
+        onConfigurationChanged(resources.configuration)
+    }
 
-    fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) {
+    private 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
+                    // Restrict emulation and overlays to the top of the screen
+                    binding.emulationContainer.layoutParams.height = it.bounds.top
+                    binding.overlayContainer.layoutParams.height = it.bounds.top
+                    // Restrict input and menu drawer to the bottom of the screen
+                    binding.inputContainer.layoutParams.height = it.bounds.bottom
                     binding.inGameMenu.layoutParams.height = it.bounds.bottom
-                    binding.overlayContainer.layoutParams.height = it.bounds.bottom - 48.toPx
-                    binding.overlayContainer.updatePadding(0, 0, 0, 24.toPx)
+
+                    isInFoldableLayout = true
+                    binding.surfaceInputOverlay.orientation = InputOverlay.FOLDABLE
+                    refreshInputOverlay()
                 }
             }
             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.inputContainer.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
+            binding.inGameMenu.layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT
+            isInFoldableLayout = false
+            updateScreenLayout()
         }
-        binding.surfaceInputOverlay.requestLayout()
-        binding.inGameMenu.requestLayout()
+        binding.emulationContainer.requestLayout()
+        binding.inputContainer.requestLayout()
         binding.overlayContainer.requestLayout()
+        binding.inGameMenu.requestLayout()
     }
 
     override fun surfaceCreated(holder: SurfaceHolder) {
@@ -397,7 +481,19 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         popup.show()
     }
 
+    @SuppressLint("SourceLockedOrientationActivity")
     private fun startConfiguringControls() {
+        // Lock the current orientation to prevent editing inconsistencies
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+            emulationActivity?.let {
+                it.requestedOrientation =
+                    if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
+                        ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT
+                    } else {
+                        ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
+                    }
+            }
+        }
         binding.doneControlConfig.visibility = View.VISIBLE
         binding.surfaceInputOverlay.setIsInEditMode(true)
     }
@@ -405,6 +501,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
     private fun stopConfiguringControls() {
         binding.doneControlConfig.visibility = View.GONE
         binding.surfaceInputOverlay.setIsInEditMode(false)
+        // Unlock the orientation if it was locked for editing
+        if (IntSetting.RENDERER_SCREEN_LAYOUT.int == Settings.LayoutOption_Unspecified) {
+            emulationActivity?.let {
+                it.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
+            }
+        }
     }
 
     @SuppressLint("SetTextI18n")
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
index aa424c768..d12d08e9f 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/overlay/InputOverlay.kt
@@ -51,12 +51,14 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
 
     private lateinit var windowInsets: WindowInsets
 
+    var orientation = LANDSCAPE
+
     override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
         super.onLayout(changed, left, top, right, bottom)
 
         windowInsets = rootWindowInsets
 
-        if (!preferences.getBoolean(Settings.PREF_OVERLAY_INIT, false)) {
+        if (!preferences.getBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", false)) {
             defaultOverlay()
         }
 
@@ -233,10 +235,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
         val fingerPositionX = event.getX(pointerIndex).toInt()
         val fingerPositionY = event.getY(pointerIndex).toInt()
 
-        // TODO: Provide support for portrait layout
-        //val orientation =
-        //    if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else ""
-
         for (button in overlayButtons) {
             // Determine the button state to apply based on the MotionEvent action flag.
             when (event.action and MotionEvent.ACTION_MASK) {
@@ -266,7 +264,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
                         buttonBeingConfigured!!.buttonId,
                         buttonBeingConfigured!!.bounds.centerX(),
                         buttonBeingConfigured!!.bounds.centerY(),
-                        ""
+                        orientation
                     )
                     buttonBeingConfigured = null
                 }
@@ -299,7 +297,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
                         dpadBeingConfigured!!.upId,
                         dpadBeingConfigured!!.bounds.centerX(),
                         dpadBeingConfigured!!.bounds.centerY(),
-                        ""
+                        orientation
                     )
                     dpadBeingConfigured = null
                 }
@@ -330,7 +328,7 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
                         joystickBeingConfigured!!.buttonId,
                         joystickBeingConfigured!!.bounds.centerX(),
                         joystickBeingConfigured!!.bounds.centerY(),
-                        ""
+                        orientation
                     )
                     joystickBeingConfigured = null
                 }
@@ -533,8 +531,6 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
         overlayButtons.clear()
         overlayDpads.clear()
         overlayJoysticks.clear()
-        val orientation =
-            if (resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT) "-Portrait" else ""
 
         // Add all the enabled overlay items back to the HashSet.
         if (EmulationMenuSettings.showOverlay) {
@@ -548,8 +544,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
         val min = windowSize.first
         val max = windowSize.second
         PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext).edit()
-            .putFloat("$sharedPrefsId$orientation-X", (x - min.x).toFloat() / max.x)
-            .putFloat("$sharedPrefsId$orientation-Y", (y - min.y).toFloat() / max.y)
+            .putFloat("$sharedPrefsId-X$orientation", (x - min.x).toFloat() / max.x)
+            .putFloat("$sharedPrefsId-Y$orientation", (y - min.y).toFloat() / max.y)
             .apply()
     }
 
@@ -558,145 +554,250 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
     }
 
     private fun defaultOverlay() {
-        if (!preferences.getBoolean(Settings.PREF_OVERLAY_INIT, false)) {
-            defaultOverlayLandscape()
+        if (!preferences.getBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", false)) {
+            defaultOverlayByLayout(orientation)
         }
 
         resetButtonPlacement()
         preferences.edit()
-            .putBoolean(Settings.PREF_OVERLAY_INIT, true)
+            .putBoolean("${Settings.PREF_OVERLAY_INIT}$orientation", true)
             .apply()
     }
 
     fun resetButtonPlacement() {
-        defaultOverlayLandscape()
+        defaultOverlayByLayout(orientation)
         refreshControls()
     }
 
-    private fun defaultOverlayLandscape() {
+    private val landscapeResources = arrayOf(
+        R.integer.SWITCH_BUTTON_A_X,
+        R.integer.SWITCH_BUTTON_A_Y,
+        R.integer.SWITCH_BUTTON_B_X,
+        R.integer.SWITCH_BUTTON_B_Y,
+        R.integer.SWITCH_BUTTON_X_X,
+        R.integer.SWITCH_BUTTON_X_Y,
+        R.integer.SWITCH_BUTTON_Y_X,
+        R.integer.SWITCH_BUTTON_Y_Y,
+        R.integer.SWITCH_TRIGGER_ZL_X,
+        R.integer.SWITCH_TRIGGER_ZL_Y,
+        R.integer.SWITCH_TRIGGER_ZR_X,
+        R.integer.SWITCH_TRIGGER_ZR_Y,
+        R.integer.SWITCH_BUTTON_DPAD_X,
+        R.integer.SWITCH_BUTTON_DPAD_Y,
+        R.integer.SWITCH_TRIGGER_L_X,
+        R.integer.SWITCH_TRIGGER_L_Y,
+        R.integer.SWITCH_TRIGGER_R_X,
+        R.integer.SWITCH_TRIGGER_R_Y,
+        R.integer.SWITCH_BUTTON_PLUS_X,
+        R.integer.SWITCH_BUTTON_PLUS_Y,
+        R.integer.SWITCH_BUTTON_MINUS_X,
+        R.integer.SWITCH_BUTTON_MINUS_Y,
+        R.integer.SWITCH_BUTTON_HOME_X,
+        R.integer.SWITCH_BUTTON_HOME_Y,
+        R.integer.SWITCH_BUTTON_CAPTURE_X,
+        R.integer.SWITCH_BUTTON_CAPTURE_Y,
+        R.integer.SWITCH_STICK_R_X,
+        R.integer.SWITCH_STICK_R_Y,
+        R.integer.SWITCH_STICK_L_X,
+        R.integer.SWITCH_STICK_L_Y
+    )
+
+    private val portraitResources = arrayOf(
+        R.integer.SWITCH_BUTTON_A_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_A_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_B_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_B_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_X_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_X_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_Y_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_Y_Y_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_ZL_X_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_ZL_Y_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_ZR_X_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_ZR_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_DPAD_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_DPAD_Y_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_L_X_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_L_Y_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_R_X_PORTRAIT,
+        R.integer.SWITCH_TRIGGER_R_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_PLUS_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_PLUS_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_MINUS_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_MINUS_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_HOME_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_HOME_Y_PORTRAIT,
+        R.integer.SWITCH_BUTTON_CAPTURE_X_PORTRAIT,
+        R.integer.SWITCH_BUTTON_CAPTURE_Y_PORTRAIT,
+        R.integer.SWITCH_STICK_R_X_PORTRAIT,
+        R.integer.SWITCH_STICK_R_Y_PORTRAIT,
+        R.integer.SWITCH_STICK_L_X_PORTRAIT,
+        R.integer.SWITCH_STICK_L_Y_PORTRAIT
+    )
+
+    private val foldableResources = arrayOf(
+        R.integer.SWITCH_BUTTON_A_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_A_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_B_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_B_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_X_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_X_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_Y_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_Y_Y_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_ZL_X_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_ZL_Y_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_ZR_X_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_ZR_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_DPAD_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_DPAD_Y_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_L_X_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_L_Y_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_R_X_FOLDABLE,
+        R.integer.SWITCH_TRIGGER_R_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_PLUS_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_PLUS_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_MINUS_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_MINUS_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_HOME_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_HOME_Y_FOLDABLE,
+        R.integer.SWITCH_BUTTON_CAPTURE_X_FOLDABLE,
+        R.integer.SWITCH_BUTTON_CAPTURE_Y_FOLDABLE,
+        R.integer.SWITCH_STICK_R_X_FOLDABLE,
+        R.integer.SWITCH_STICK_R_Y_FOLDABLE,
+        R.integer.SWITCH_STICK_L_X_FOLDABLE,
+        R.integer.SWITCH_STICK_L_Y_FOLDABLE
+    )
+
+    private fun getResourceValue(orientation: String, position: Int) : Float {
+        return when (orientation) {
+            PORTRAIT -> resources.getInteger(portraitResources[position]).toFloat() / 1000
+            FOLDABLE -> resources.getInteger(foldableResources[position]).toFloat() / 1000
+            else -> resources.getInteger(landscapeResources[position]).toFloat() / 1000
+        }
+    }
+
+    private fun defaultOverlayByLayout(orientation: String) {
         // Each value represents the position of the button in relation to the screen size without insets.
         preferences.edit()
             .putFloat(
-                ButtonType.BUTTON_A.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_A_X).toFloat() / 1000
+                ButtonType.BUTTON_A.toString() + "-X$orientation",
+                getResourceValue(orientation, 0)
             )
             .putFloat(
-                ButtonType.BUTTON_A.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_A_Y).toFloat() / 1000
+                ButtonType.BUTTON_A.toString() + "-Y$orientation",
+                getResourceValue(orientation, 1)
             )
             .putFloat(
-                ButtonType.BUTTON_B.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_B_X).toFloat() / 1000
+                ButtonType.BUTTON_B.toString() + "-X$orientation",
+                getResourceValue(orientation, 2)
             )
             .putFloat(
-                ButtonType.BUTTON_B.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_B_Y).toFloat() / 1000
+                ButtonType.BUTTON_B.toString() + "-Y$orientation",
+                getResourceValue(orientation, 3)
             )
             .putFloat(
-                ButtonType.BUTTON_X.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_X_X).toFloat() / 1000
+                ButtonType.BUTTON_X.toString() + "-X$orientation",
+                getResourceValue(orientation, 4)
             )
             .putFloat(
-                ButtonType.BUTTON_X.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_X_Y).toFloat() / 1000
+                ButtonType.BUTTON_X.toString() + "-Y$orientation",
+                getResourceValue(orientation, 5)
             )
             .putFloat(
-                ButtonType.BUTTON_Y.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_Y_X).toFloat() / 1000
+                ButtonType.BUTTON_Y.toString() + "-X$orientation",
+                getResourceValue(orientation, 6)
             )
             .putFloat(
-                ButtonType.BUTTON_Y.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_Y_Y).toFloat() / 1000
+                ButtonType.BUTTON_Y.toString() + "-Y$orientation",
+                getResourceValue(orientation, 7)
             )
             .putFloat(
-                ButtonType.TRIGGER_ZL.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_X).toFloat() / 1000
+                ButtonType.TRIGGER_ZL.toString() + "-X$orientation",
+                getResourceValue(orientation, 8)
             )
             .putFloat(
-                ButtonType.TRIGGER_ZL.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_ZL_Y).toFloat() / 1000
+                ButtonType.TRIGGER_ZL.toString() + "-Y$orientation",
+                getResourceValue(orientation, 9)
             )
             .putFloat(
-                ButtonType.TRIGGER_ZR.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_X).toFloat() / 1000
+                ButtonType.TRIGGER_ZR.toString() + "-X$orientation",
+                getResourceValue(orientation, 10)
             )
             .putFloat(
-                ButtonType.TRIGGER_ZR.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_ZR_Y).toFloat() / 1000
+                ButtonType.TRIGGER_ZR.toString() + "-Y$orientation",
+                getResourceValue(orientation, 11)
             )
             .putFloat(
-                ButtonType.DPAD_UP.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_X).toFloat() / 1000
+                ButtonType.DPAD_UP.toString() + "-X$orientation",
+                getResourceValue(orientation, 12)
             )
             .putFloat(
-                ButtonType.DPAD_UP.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_DPAD_Y).toFloat() / 1000
+                ButtonType.DPAD_UP.toString() + "-Y$orientation",
+                getResourceValue(orientation, 13)
             )
             .putFloat(
-                ButtonType.TRIGGER_L.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_L_X).toFloat() / 1000
+                ButtonType.TRIGGER_L.toString() + "-X$orientation",
+                getResourceValue(orientation, 14)
             )
             .putFloat(
-                ButtonType.TRIGGER_L.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_L_Y).toFloat() / 1000
+                ButtonType.TRIGGER_L.toString() + "-Y$orientation",
+                getResourceValue(orientation, 15)
             )
             .putFloat(
-                ButtonType.TRIGGER_R.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_R_X).toFloat() / 1000
+                ButtonType.TRIGGER_R.toString() + "-X$orientation",
+                getResourceValue(orientation, 16)
             )
             .putFloat(
-                ButtonType.TRIGGER_R.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_TRIGGER_R_Y).toFloat() / 1000
+                ButtonType.TRIGGER_R.toString() + "-Y$orientation",
+                getResourceValue(orientation, 17)
             )
             .putFloat(
-                ButtonType.BUTTON_PLUS.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_X).toFloat() / 1000
+                ButtonType.BUTTON_PLUS.toString() + "-X$orientation",
+                getResourceValue(orientation, 18)
             )
             .putFloat(
-                ButtonType.BUTTON_PLUS.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_PLUS_Y).toFloat() / 1000
+                ButtonType.BUTTON_PLUS.toString() + "-Y$orientation",
+                getResourceValue(orientation, 19)
             )
             .putFloat(
-                ButtonType.BUTTON_MINUS.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_X).toFloat() / 1000
+                ButtonType.BUTTON_MINUS.toString() + "-X$orientation",
+                getResourceValue(orientation, 20)
             )
             .putFloat(
-                ButtonType.BUTTON_MINUS.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_MINUS_Y).toFloat() / 1000
+                ButtonType.BUTTON_MINUS.toString() + "-Y$orientation",
+                getResourceValue(orientation, 21)
             )
             .putFloat(
-                ButtonType.BUTTON_HOME.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_HOME_X).toFloat() / 1000
+                ButtonType.BUTTON_HOME.toString() + "-X$orientation",
+                getResourceValue(orientation, 22)
             )
             .putFloat(
-                ButtonType.BUTTON_HOME.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_HOME_Y).toFloat() / 1000
+                ButtonType.BUTTON_HOME.toString() + "-Y$orientation",
+                getResourceValue(orientation, 23)
             )
             .putFloat(
-                ButtonType.BUTTON_CAPTURE.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_X)
-                    .toFloat() / 1000
+                ButtonType.BUTTON_CAPTURE.toString() + "-X$orientation",
+                getResourceValue(orientation, 24)
             )
             .putFloat(
-                ButtonType.BUTTON_CAPTURE.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_BUTTON_CAPTURE_Y)
-                    .toFloat() / 1000
+                ButtonType.BUTTON_CAPTURE.toString() + "-Y$orientation",
+                getResourceValue(orientation, 25)
             )
             .putFloat(
-                ButtonType.STICK_R.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_STICK_R_X).toFloat() / 1000
+                ButtonType.STICK_R.toString() + "-X$orientation",
+                getResourceValue(orientation, 26)
             )
             .putFloat(
-                ButtonType.STICK_R.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_STICK_R_Y).toFloat() / 1000
+                ButtonType.STICK_R.toString() + "-Y$orientation",
+                getResourceValue(orientation, 27)
             )
             .putFloat(
-                ButtonType.STICK_L.toString() + "-X",
-                resources.getInteger(R.integer.SWITCH_STICK_L_X).toFloat() / 1000
+                ButtonType.STICK_L.toString() + "-X$orientation",
+                getResourceValue(orientation, 28)
             )
             .putFloat(
-                ButtonType.STICK_L.toString() + "-Y",
-                resources.getInteger(R.integer.SWITCH_STICK_L_Y).toFloat() / 1000
+                ButtonType.STICK_L.toString() + "-Y$orientation",
+                getResourceValue(orientation, 29)
             )
             .apply()
     }
@@ -709,6 +810,10 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
         private val preferences: SharedPreferences =
             PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
 
+        const val LANDSCAPE = ""
+        const val PORTRAIT = "_Portrait"
+        const val FOLDABLE = "_Foldable"
+
         /**
          * Resizes a [Bitmap] by a given scale factor
          *
@@ -754,9 +859,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
          */
         private fun getSafeScreenSize(context: Context): Pair<Point, Point> {
             // Get screen size
-            val windowMetrics =
-                WindowMetricsCalculator.getOrCreate()
-                    .computeCurrentWindowMetrics(context as Activity)
+            val windowMetrics = WindowMetricsCalculator.getOrCreate()
+                .computeCurrentWindowMetrics(context as Activity)
             var maxY = windowMetrics.bounds.height().toFloat()
             var maxX = windowMetrics.bounds.width().toFloat()
             var minY = 0
@@ -769,9 +873,9 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
                 val insets = context.windowManager.currentWindowMetrics.windowInsets.displayCutout
                 if (insets != null) {
                     if (insets.boundingRectTop.bottom != 0 && insets.boundingRectTop.bottom > maxY / 2)
-                        insets.boundingRectTop.bottom.toFloat() else maxY
+                        maxY = insets.boundingRectTop.bottom.toFloat()
                     if (insets.boundingRectRight.left != 0 && insets.boundingRectRight.left > maxX / 2)
-                        insets.boundingRectRight.left.toFloat() else maxX
+                        maxX = insets.boundingRectRight.left.toFloat()
 
                     minX = insets.boundingRectLeft.right - insets.boundingRectLeft.left
                     minY = insets.boundingRectBottom.top - insets.boundingRectBottom.bottom
@@ -878,8 +982,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
 
             // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
             // These were set in the input overlay configuration menu.
-            val xKey = "$buttonId$orientation-X"
-            val yKey = "$buttonId$orientation-Y"
+            val xKey = "$buttonId-X$orientation"
+            val yKey = "$buttonId-Y$orientation"
             val drawableXPercent = sPrefs.getFloat(xKey, 0f)
             val drawableYPercent = sPrefs.getFloat(yKey, 0f)
             val drawableX = (drawableXPercent * max.x + min.x).toInt()
@@ -959,8 +1063,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
 
             // The X and Y coordinates of the InputOverlayDrawableDpad on the InputOverlay.
             // These were set in the input overlay configuration menu.
-            val drawableXPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-X", 0f)
-            val drawableYPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}$orientation-Y", 0f)
+            val drawableXPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}-X$orientation", 0f)
+            val drawableYPercent = sPrefs.getFloat("${ButtonType.DPAD_UP}-Y$orientation", 0f)
             val drawableX = (drawableXPercent * max.x + min.x).toInt()
             val drawableY = (drawableYPercent * max.y + min.y).toInt()
             val width = overlayDrawable.width
@@ -1026,8 +1130,8 @@ class InputOverlay(context: Context, attrs: AttributeSet?) : SurfaceView(context
 
             // The X and Y coordinates of the InputOverlayDrawableButton on the InputOverlay.
             // These were set in the input overlay configuration menu.
-            val drawableXPercent = sPrefs.getFloat("$button$orientation-X", 0f)
-            val drawableYPercent = sPrefs.getFloat("$button$orientation-Y", 0f)
+            val drawableXPercent = sPrefs.getFloat("$button-X$orientation", 0f)
+            val drawableYPercent = sPrefs.getFloat("$button-Y$orientation", 0f)
             val drawableX = (drawableXPercent * max.x + min.x).toInt()
             val drawableY = (drawableYPercent * max.y + min.y).toInt()
             val outerScale = 1.66f
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt
index e1e7a59d7..7e8f058c1 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/EmulationMenuSettings.kt
@@ -11,14 +11,6 @@ object EmulationMenuSettings {
     private val preferences =
         PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
 
-    // These must match what is defined in src/core/settings.h
-    const val LayoutOption_Default = 0
-    const val LayoutOption_SingleScreen = 1
-    const val LayoutOption_LargeScreen = 2
-    const val LayoutOption_SideScreen = 3
-    const val LayoutOption_MobilePortrait = 4
-    const val LayoutOption_MobileLandscape = 5
-
     var joystickRelCenter: Boolean
         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER, true)
         set(value) {
@@ -41,16 +33,6 @@ object EmulationMenuSettings {
                 .apply()
         }
 
-    var landscapeScreenLayout: Int
-        get() = preferences.getInt(
-            Settings.PREF_MENU_SETTINGS_LANDSCAPE,
-            LayoutOption_MobileLandscape
-        )
-        set(value) {
-            preferences.edit()
-                .putInt(Settings.PREF_MENU_SETTINGS_LANDSCAPE, value)
-                .apply()
-        }
     var showFps: Boolean
         get() = preferences.getBoolean(Settings.PREF_MENU_SETTINGS_SHOW_FPS, false)
         set(value) {
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
index 4091c23d1..f9617202b 100644
--- a/src/android/app/src/main/jni/native.cpp
+++ b/src/android/app/src/main/jni/native.cpp
@@ -202,6 +202,11 @@ public:
         return m_is_running;
     }
 
+    bool IsPaused() const {
+        std::scoped_lock lock(m_mutex);
+        return m_is_running && m_is_paused;
+    }
+
     const Core::PerfStatsResults& PerfStats() const {
         std::scoped_lock m_perf_stats_lock(m_perf_stats_mutex);
         return m_perf_stats;
@@ -287,11 +292,13 @@ public:
     void PauseEmulation() {
         std::scoped_lock lock(m_mutex);
         m_system.Pause();
+        m_is_paused = true;
     }
 
     void UnPauseEmulation() {
         std::scoped_lock lock(m_mutex);
         m_system.Run();
+        m_is_paused = false;
     }
 
     void HaltEmulation() {
@@ -473,6 +480,7 @@ private:
     std::shared_ptr<FileSys::VfsFilesystem> m_vfs;
     Core::SystemResultStatus m_load_result{Core::SystemResultStatus::ErrorNotInitialized};
     bool m_is_running{};
+    bool m_is_paused{};
     SoftwareKeyboard::AndroidKeyboard* m_software_keyboard{};
     std::unique_ptr<Service::Account::ProfileManager> m_profile_manager;
 
@@ -583,6 +591,11 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv
     return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
 }
 
+jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused([[maybe_unused]] JNIEnv* env,
+                                                        [[maybe_unused]] jclass clazz) {
+    return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
+}
+
 jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHandheldOnly([[maybe_unused]] JNIEnv* env,
                                                               [[maybe_unused]] jclass clazz) {
     return EmulationSession::GetInstance().IsHandheldOnly();
diff --git a/src/android/app/src/main/res/drawable/ic_pip_pause.xml b/src/android/app/src/main/res/drawable/ic_pip_pause.xml
new file mode 100644
index 000000000..4a7d4ea03
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_pip_pause.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z" />
+</vector>
diff --git a/src/android/app/src/main/res/drawable/ic_pip_play.xml b/src/android/app/src/main/res/drawable/ic_pip_play.xml
new file mode 100644
index 000000000..2303a4623
--- /dev/null
+++ b/src/android/app/src/main/res/drawable/ic_pip_play.xml
@@ -0,0 +1,9 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M8,5v14l11,-7z" />
+</vector>
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 09b789b6b..e54a10e8f 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -12,49 +12,65 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent">
 
-        <!-- This is what everything is rendered to during emulation -->
-        <org.yuzu.yuzu_emu.views.FixedRatioSurfaceView
-            android:id="@+id/surface_emulation"
+        <FrameLayout
+            android:id="@+id/emulation_container"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:layout_gravity="center"
-            android:focusable="false"
-            android:focusableInTouchMode="false" />
+            android:layout_height="match_parent">
+
+            <!-- This is what everything is rendered to during emulation -->
+            <org.yuzu.yuzu_emu.views.FixedRatioSurfaceView
+                android:id="@+id/surface_emulation"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:focusable="false"
+                android:focusableInTouchMode="false" />
+
+        </FrameLayout>
 
         <FrameLayout
-            android:id="@+id/overlay_container"
+            android:id="@+id/input_container"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:layout_gravity="bottom">
 
-        <!-- This is the onscreen input overlay -->
-        <org.yuzu.yuzu_emu.overlay.InputOverlay
-            android:id="@+id/surface_input_overlay"
+            <!-- This is the onscreen input overlay -->
+            <org.yuzu.yuzu_emu.overlay.InputOverlay
+                android:id="@+id/surface_input_overlay"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_gravity="center"
+                android:focusable="true"
+                android:focusableInTouchMode="true" />
+
+            <Button
+                style="@style/Widget.Material3.Button.ElevatedButton"
+                android:id="@+id/done_control_config"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="center"
+                android:text="@string/emulation_done"
+                android:visibility="gone" />
+
+        </FrameLayout>
+
+        <FrameLayout
+            android:id="@+id/overlay_container"
             android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:focusable="true"
-            android:focusableInTouchMode="true" />
+            android:layout_height="match_parent">
 
-        <TextView
-            android:id="@+id/show_fps_text"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="left"
-            android:clickable="false"
-            android:focusable="false"
-            android:shadowColor="@android:color/black"
-            android:textColor="@android:color/white"
-            android:textSize="12sp"
-            tools:ignore="RtlHardcoded" />
+            <TextView
+                android:id="@+id/show_fps_text"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="left"
+                android:clickable="false"
+                android:focusable="false"
+                android:shadowColor="@android:color/black"
+                android:textColor="@android:color/white"
+                android:textSize="12sp"
+                tools:ignore="RtlHardcoded" />
 
-        <Button
-            style="@style/Widget.Material3.Button.ElevatedButton"
-            android:id="@+id/done_control_config"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center"
-            android:text="@string/emulation_done"
-            android:visibility="gone" />
         </FrameLayout>
 
     </androidx.coordinatorlayout.widget.CoordinatorLayout>
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml
index ea20cb17c..7f7b1938c 100644
--- a/src/android/app/src/main/res/values/arrays.xml
+++ b/src/android/app/src/main/res/values/arrays.xml
@@ -119,6 +119,18 @@
         <item>3</item>
     </integer-array>
 
+    <string-array name="rendererScreenLayoutNames">
+        <item>@string/screen_layout_landscape</item>
+        <item>@string/screen_layout_portrait</item>
+        <item>@string/screen_layout_auto</item>
+    </string-array>
+
+    <integer-array name="rendererScreenLayoutValues">
+        <item>5</item>
+        <item>4</item>
+        <item>0</item>
+    </integer-array>
+
     <string-array name="rendererAspectRatioNames">
         <item>@string/ratio_default</item>
         <item>@string/ratio_force_four_three</item>
diff --git a/src/android/app/src/main/res/values/integers.xml b/src/android/app/src/main/res/values/integers.xml
index bc614b81d..2e93b408c 100644
--- a/src/android/app/src/main/res/values/integers.xml
+++ b/src/android/app/src/main/res/values/integers.xml
@@ -34,4 +34,68 @@
     <integer name="SWITCH_BUTTON_DPAD_X">260</integer>
     <integer name="SWITCH_BUTTON_DPAD_Y">790</integer>
 
+    <!-- Default SWITCH portrait layout -->
+    <integer name="SWITCH_BUTTON_A_X_PORTRAIT">840</integer>
+    <integer name="SWITCH_BUTTON_A_Y_PORTRAIT">840</integer>
+    <integer name="SWITCH_BUTTON_B_X_PORTRAIT">740</integer>
+    <integer name="SWITCH_BUTTON_B_Y_PORTRAIT">880</integer>
+    <integer name="SWITCH_BUTTON_X_X_PORTRAIT">740</integer>
+    <integer name="SWITCH_BUTTON_X_Y_PORTRAIT">800</integer>
+    <integer name="SWITCH_BUTTON_Y_X_PORTRAIT">640</integer>
+    <integer name="SWITCH_BUTTON_Y_Y_PORTRAIT">840</integer>
+    <integer name="SWITCH_STICK_L_X_PORTRAIT">180</integer>
+    <integer name="SWITCH_STICK_L_Y_PORTRAIT">660</integer>
+    <integer name="SWITCH_STICK_R_X_PORTRAIT">820</integer>
+    <integer name="SWITCH_STICK_R_Y_PORTRAIT">660</integer>
+    <integer name="SWITCH_TRIGGER_L_X_PORTRAIT">140</integer>
+    <integer name="SWITCH_TRIGGER_L_Y_PORTRAIT">260</integer>
+    <integer name="SWITCH_TRIGGER_R_X_PORTRAIT">860</integer>
+    <integer name="SWITCH_TRIGGER_R_Y_PORTRAIT">260</integer>
+    <integer name="SWITCH_TRIGGER_ZL_X_PORTRAIT">140</integer>
+    <integer name="SWITCH_TRIGGER_ZL_Y_PORTRAIT">200</integer>
+    <integer name="SWITCH_TRIGGER_ZR_X_PORTRAIT">860</integer>
+    <integer name="SWITCH_TRIGGER_ZR_Y_PORTRAIT">200</integer>
+    <integer name="SWITCH_BUTTON_MINUS_X_PORTRAIT">440</integer>
+    <integer name="SWITCH_BUTTON_MINUS_Y_PORTRAIT">950</integer>
+    <integer name="SWITCH_BUTTON_PLUS_X_PORTRAIT">560</integer>
+    <integer name="SWITCH_BUTTON_PLUS_Y_PORTRAIT">950</integer>
+    <integer name="SWITCH_BUTTON_HOME_X_PORTRAIT">680</integer>
+    <integer name="SWITCH_BUTTON_HOME_Y_PORTRAIT">950</integer>
+    <integer name="SWITCH_BUTTON_CAPTURE_X_PORTRAIT">320</integer>
+    <integer name="SWITCH_BUTTON_CAPTURE_Y_PORTRAIT">950</integer>
+    <integer name="SWITCH_BUTTON_DPAD_X_PORTRAIT">240</integer>
+    <integer name="SWITCH_BUTTON_DPAD_Y_PORTRAIT">840</integer>
+
+    <!-- Default SWITCH foldable layout -->
+    <integer name="SWITCH_BUTTON_A_X_FOLDABLE">840</integer>
+    <integer name="SWITCH_BUTTON_A_Y_FOLDABLE">390</integer>
+    <integer name="SWITCH_BUTTON_B_X_FOLDABLE">740</integer>
+    <integer name="SWITCH_BUTTON_B_Y_FOLDABLE">430</integer>
+    <integer name="SWITCH_BUTTON_X_X_FOLDABLE">740</integer>
+    <integer name="SWITCH_BUTTON_X_Y_FOLDABLE">350</integer>
+    <integer name="SWITCH_BUTTON_Y_X_FOLDABLE">640</integer>
+    <integer name="SWITCH_BUTTON_Y_Y_FOLDABLE">390</integer>
+    <integer name="SWITCH_STICK_L_X_FOLDABLE">180</integer>
+    <integer name="SWITCH_STICK_L_Y_FOLDABLE">250</integer>
+    <integer name="SWITCH_STICK_R_X_FOLDABLE">820</integer>
+    <integer name="SWITCH_STICK_R_Y_FOLDABLE">250</integer>
+    <integer name="SWITCH_TRIGGER_L_X_FOLDABLE">140</integer>
+    <integer name="SWITCH_TRIGGER_L_Y_FOLDABLE">130</integer>
+    <integer name="SWITCH_TRIGGER_R_X_FOLDABLE">860</integer>
+    <integer name="SWITCH_TRIGGER_R_Y_FOLDABLE">130</integer>
+    <integer name="SWITCH_TRIGGER_ZL_X_FOLDABLE">140</integer>
+    <integer name="SWITCH_TRIGGER_ZL_Y_FOLDABLE">70</integer>
+    <integer name="SWITCH_TRIGGER_ZR_X_FOLDABLE">860</integer>
+    <integer name="SWITCH_TRIGGER_ZR_Y_FOLDABLE">70</integer>
+    <integer name="SWITCH_BUTTON_MINUS_X_FOLDABLE">440</integer>
+    <integer name="SWITCH_BUTTON_MINUS_Y_FOLDABLE">470</integer>
+    <integer name="SWITCH_BUTTON_PLUS_X_FOLDABLE">560</integer>
+    <integer name="SWITCH_BUTTON_PLUS_Y_FOLDABLE">470</integer>
+    <integer name="SWITCH_BUTTON_HOME_X_FOLDABLE">680</integer>
+    <integer name="SWITCH_BUTTON_HOME_Y_FOLDABLE">470</integer>
+    <integer name="SWITCH_BUTTON_CAPTURE_X_FOLDABLE">320</integer>
+    <integer name="SWITCH_BUTTON_CAPTURE_Y_FOLDABLE">470</integer>
+    <integer name="SWITCH_BUTTON_DPAD_X_FOLDABLE">240</integer>
+    <integer name="SWITCH_BUTTON_DPAD_Y_FOLDABLE">390</integer>
+
 </resources>
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index c236811fa..b5bc249d4 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -162,6 +162,7 @@
     <string name="renderer_accuracy">Accuracy level</string>
     <string name="renderer_resolution">Resolution (Handheld/Docked)</string>
     <string name="renderer_vsync">VSync mode</string>
+    <string name="renderer_screen_layout">Orientation</string>
     <string name="renderer_aspect_ratio">Aspect ratio</string>
     <string name="renderer_scaling_filter">Window adapting filter</string>
     <string name="renderer_anti_aliasing">Anti-aliasing method</string>
@@ -326,6 +327,11 @@
     <string name="anti_aliasing_fxaa">FXAA</string>
     <string name="anti_aliasing_smaa">SMAA</string>
 
+    <!-- Screen Layouts -->
+    <string name="screen_layout_landscape">Landscape</string>
+    <string name="screen_layout_portrait">Portrait</string>
+    <string name="screen_layout_auto">Auto</string>
+
     <!-- Aspect Ratios -->
     <string name="ratio_default">Default (16:9)</string>
     <string name="ratio_force_four_three">Force 4:3</string>
@@ -364,6 +370,12 @@
     <string name="use_black_backgrounds">Black backgrounds</string>
     <string name="use_black_backgrounds_description">When using the dark theme, apply black backgrounds.</string>
 
+    <!-- Picture-In-Picture -->
+    <string name="picture_in_picture">Picture in Picture</string>
+    <string name="picture_in_picture_description">Minimize window when placed in the background</string>
+    <string name="pause">Pause</string>
+    <string name="play">Play</string>
+
     <!-- Licenses screen strings -->
     <string name="licenses">Licenses</string>
     <string name="license_fidelityfx_fsr" translatable="false">FidelityFX-FSR</string>