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 4c6be497ec..2a5e52cff8 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 @@ -31,7 +31,6 @@ import android.view.View import android.view.inputmethod.InputMethodManager import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity -import androidx.core.content.getSystemService import androidx.core.view.WindowCompat import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsControllerCompat @@ -45,11 +44,11 @@ import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.R 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.Settings import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel import org.yuzu.yuzu_emu.fragments.EmulationFragment import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.utils.ControllerMappingHelper -import org.yuzu.yuzu_emu.utils.EmulationMenuSettings import org.yuzu.yuzu_emu.utils.ForegroundService import org.yuzu.yuzu_emu.utils.InputHandler import org.yuzu.yuzu_emu.utils.NfcReader @@ -163,8 +162,8 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { startMotionSensorListener() NativeLibrary.notifyOrientationChange( - EmulationMenuSettings.landscapeScreenLayout, - getAdjustedRotation() + Settings.LayoutOption_MobileLandscape, + Surface.ROTATION_90 ) val pictureInPictureParamsBuilder = PictureInPictureParams.Builder() @@ -288,23 +287,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { override fun onAccuracyChanged(sensor: Sensor, i: Int) {} - private fun getAdjustedRotation():Int { - val rotation = getSystemService()!!.getDisplay(Display.DEFAULT_DISPLAY).rotation - val config: Configuration = resources.configuration - - if ((config.screenLayout and Configuration.SCREENLAYOUT_LONG_YES) != 0 || - (config.screenLayout and Configuration.SCREENLAYOUT_LONG_NO) == 0) { - return rotation - } - when (rotation) { - Surface.ROTATION_0 -> return Surface.ROTATION_90 - Surface.ROTATION_90 -> return Surface.ROTATION_0 - Surface.ROTATION_180 -> return Surface.ROTATION_270 - Surface.ROTATION_270 -> return Surface.ROTATION_180 - } - return rotation - } - private fun restoreState(savedInstanceState: Bundle) { game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!! } @@ -354,15 +336,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { return this.apply { setActions(pictureInPictureActions) } } - fun setPictureInPictureParamsExternal() { - 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) { 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 c5722a5a17..8fecd22071 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 @@ -88,6 +88,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 8df20b928f..4f753955b8 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,14 @@ class Settings { private val configFileSectionsMap: MutableMap> = HashMap() + // 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 + 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 72e2cce2ac..3853845ce7 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,12 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { settings.putExtra(ARG_GAME_ID, gameId) context.startActivity(settings) } + + fun launch(context: Context, launcher: ActivityResultLauncher, 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 157ae2bc11..ce20d8c8de 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 @@ -292,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 2aa3f6e969..1572190bad 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,10 +7,13 @@ 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.Configuration import android.content.res.Resources import android.graphics.Color +import android.hardware.display.DisplayManager import android.os.Bundle import android.os.Handler import android.os.Looper @@ -18,7 +21,10 @@ 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.getSystemService import androidx.core.content.res.ResourcesCompat import androidx.core.graphics.Insets import androidx.core.view.ViewCompat @@ -37,6 +43,7 @@ import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.activities.EmulationActivity import org.yuzu.yuzu_emu.databinding.DialogOverlayAdjustBinding import org.yuzu.yuzu_emu.databinding.FragmentEmulationBinding +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 @@ -55,11 +62,19 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private lateinit var game: Game + private lateinit var onReturnFromSettings: ActivityResultLauncher + override fun onAttach(context: Context) { super.onAttach(context) if (context is EmulationActivity) { emulationActivity = context NativeLibrary.setEmulationActivity(context) + + onReturnFromSettings = context.activityResultRegistry.register( + "SettingsResult", ActivityResultContracts.StartActivityForResult() + ) { + updateScreenLayout() + } } else { throw IllegalStateException("EmulationFragment must have EmulationActivity parent") } @@ -124,7 +139,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 } @@ -179,6 +196,38 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { super.onDetach() } + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + + val emulatorLayout = when (newConfig.orientation) { + Configuration.ORIENTATION_LANDSCAPE -> { Settings.LayoutOption_MobileLandscape } + Configuration.ORIENTATION_PORTRAIT -> { Settings.LayoutOption_MobilePortrait } + else -> { Settings.LayoutOption_MobilePortrait } + } + + emulationActivity?.let { + var rotation = it.getSystemService()!! + .getDisplay(Display.DEFAULT_DISPLAY).rotation + if (it.isInPictureInPictureMode) { + NativeLibrary.notifyOrientationChange( + Settings.LayoutOption_MobileLandscape, + Surface.ROTATION_90 + ) + } else { + if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) { + rotation = when (rotation) { + Surface.ROTATION_0 -> Surface.ROTATION_90 + Surface.ROTATION_90 -> Surface.ROTATION_0 + Surface.ROTATION_180 -> Surface.ROTATION_270 + Surface.ROTATION_270 -> Surface.ROTATION_180 + else -> { rotation } + } + } + NativeLibrary.notifyOrientationChange(emulatorLayout, rotation) + } + } + } + fun isEmulationStatePaused() : Boolean { return this::emulationState.isInitialized && emulationState.isPaused } @@ -249,6 +298,25 @@ 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 } + } + onConfigurationChanged(resources.configuration) + } + } + private val Number.toPx get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), Resources.getSystem().displayMetrics).toInt() fun updateCurrentLayout(emulationActivity: EmulationActivity, newLayoutInfo: WindowLayoutInfo) { @@ -269,7 +337,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { binding.inGameMenu.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() 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 e1e7a59d7c..7e8f058c14 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/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index ea20cb17c3..7f7b1938c3 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 @@ 3 + + @string/screen_layout_landscape + @string/screen_layout_portrait + @string/screen_layout_auto + + + + 5 + 4 + 0 + + @string/ratio_default @string/ratio_force_four_three diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index b51ee0db88..9cb4607ffd 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml @@ -156,6 +156,7 @@ Accuracy level Resolution (Handheld/Docked) VSync mode + Orientation Aspect ratio Window adapting filter Anti-aliasing method @@ -318,6 +319,11 @@ FXAA SMAA + + Landscape + Portrait + Auto + Default (16:9) Force 4:3