From c8b91b3a8940f894f5a2a64e7e522fd69b9c4b7f Mon Sep 17 00:00:00 2001
From: Charles Lombardo <clombardo169@gmail.com>
Date: Mon, 5 Jun 2023 20:24:36 -0400
Subject: [PATCH] android: Use a custom view for changing emulation aspect
 ratio

Credit to the Skyline team for the FixedRatioSurfaceView.
---
 .../yuzu_emu/fragments/EmulationFragment.kt   | 14 ++++++
 .../yuzu_emu/views/FixedRatioSurfaceView.kt   | 46 +++++++++++++++++++
 .../main/res/layout/fragment_emulation.xml    |  3 +-
 3 files changed, 62 insertions(+), 1 deletion(-)
 create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt

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 41b1a6e239..9523381cd3 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
@@ -14,6 +14,7 @@ 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
@@ -36,6 +37,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
@@ -158,6 +160,18 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
         if (!DirectoryInitialization.areDirectoriesReady) {
             DirectoryInitialization.start(requireContext())
         }
+
+        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)
+            }
+        )
+
         emulationState.run(emulationActivity!!.isActivityRecreated)
     }
 
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt
new file mode 100644
index 0000000000..c8ef8c1fdb
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/views/FixedRatioSurfaceView.kt
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.yuzu.yuzu_emu.views
+
+import android.content.Context
+import android.util.AttributeSet
+import android.util.Rational
+import android.view.SurfaceView
+import kotlin.math.roundToInt
+
+class FixedRatioSurfaceView @JvmOverloads constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0
+) : SurfaceView(context, attrs, defStyleAttr) {
+    private var aspectRatio: Float = 0f // (width / height), 0f is a special value for stretch
+
+    /**
+     * Sets the desired aspect ratio for this view
+     * @param ratio the ratio to force the view to, or null to stretch to fit
+     */
+    fun setAspectRatio(ratio: Rational?) {
+        aspectRatio = ratio?.toFloat() ?: 0f
+    }
+
+    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+        val width = MeasureSpec.getSize(widthMeasureSpec)
+        val height = MeasureSpec.getSize(heightMeasureSpec)
+        if (aspectRatio != 0f) {
+            val newWidth: Int
+            val newHeight: Int
+            if (height * aspectRatio < width) {
+                newWidth = (height * aspectRatio).roundToInt()
+                newHeight = height
+            } else {
+                newWidth = width
+                newHeight = (width / aspectRatio).roundToInt()
+            }
+            setMeasuredDimension(newWidth, newHeight)
+        } else {
+            setMeasuredDimension(width, height)
+        }
+    }
+}
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 940dbd4bf7..09b789b6b0 100644
--- a/src/android/app/src/main/res/layout/fragment_emulation.xml
+++ b/src/android/app/src/main/res/layout/fragment_emulation.xml
@@ -13,10 +13,11 @@
         android:layout_height="match_parent">
 
         <!-- This is what everything is rendered to during emulation -->
-        <SurfaceView
+        <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" />