diff options
9 files changed, 86 insertions, 74 deletions
| diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index fe613d339..a637db78a 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -9,6 +9,7 @@ plugins {      id("org.jetbrains.kotlin.android")      id("kotlin-parcelize")      kotlin("plugin.serialization") version "1.8.21" +    id("androidx.navigation.safeargs.kotlin")  }  /** diff --git a/src/android/app/src/main/AndroidManifest.xml b/src/android/app/src/main/AndroidManifest.xml index 55f62b4b9..b474ddb0b 100644 --- a/src/android/app/src/main/AndroidManifest.xml +++ b/src/android/app/src/main/AndroidManifest.xml @@ -53,7 +53,6 @@ SPDX-License-Identifier: GPL-3.0-or-later          <activity              android:name="org.yuzu.yuzu_emu.activities.EmulationActivity"              android:theme="@style/Theme.Yuzu.Main" -            android:launchMode="singleTop"              android:screenOrientation="userLandscape"              android:exported="true"> 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 20a0394f5..caf660348 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 @@ -23,30 +23,25 @@ import androidx.appcompat.app.AppCompatActivity  import androidx.core.view.WindowCompat  import androidx.core.view.WindowInsetsCompat  import androidx.core.view.WindowInsetsControllerCompat -import androidx.lifecycle.Lifecycle -import androidx.lifecycle.lifecycleScope -import androidx.lifecycle.repeatOnLifecycle -import androidx.window.layout.WindowInfoTracker -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch +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.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.ForegroundService  import org.yuzu.yuzu_emu.utils.InputHandler  import org.yuzu.yuzu_emu.utils.NfcReader -import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable  import org.yuzu.yuzu_emu.utils.ThemeHelper  import kotlin.math.roundToInt  class EmulationActivity : AppCompatActivity(), SensorEventListener { +    private lateinit var binding: ActivityEmulationBinding +      private var controllerMappingHelper: ControllerMappingHelper? = null      var isActivityRecreated = false -    private var emulationFragment: EmulationFragment? = null      private lateinit var nfcReader: NfcReader      private lateinit var inputHandler: InputHandler @@ -55,8 +50,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {      private var motionTimestamp: Long = 0      private var flipMotionOrientation: Boolean = false -    private lateinit var game: Game -      private val settingsViewModel: SettingsViewModel by viewModels()      override fun onDestroy() { @@ -70,47 +63,31 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {          settingsViewModel.settings.loadSettings()          super.onCreate(savedInstanceState) -        if (savedInstanceState == null) { -            // Get params we were passed -            game = intent.parcelable(EXTRA_SELECTED_GAME)!! -            isActivityRecreated = false -        } else { -            isActivityRecreated = true -            restoreState(savedInstanceState) -        } + +        binding = ActivityEmulationBinding.inflate(layoutInflater) +        setContentView(binding.root) + +        val navHostFragment = +            supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment +        val navController = navHostFragment.navController +        navController +            .setGraph(R.navigation.emulation_navigation, intent.extras) + +        isActivityRecreated = savedInstanceState != null +          controllerMappingHelper = ControllerMappingHelper()          // Set these options now so that the SurfaceView the game renders into is the right size.          enableFullscreenImmersive() -        setContentView(R.layout.activity_emulation)          window.decorView.setBackgroundColor(getColor(android.R.color.black)) -        // Find or create the EmulationFragment -        emulationFragment = -            supportFragmentManager.findFragmentById(R.id.frame_emulation_fragment) as EmulationFragment? -        if (emulationFragment == null) { -            emulationFragment = EmulationFragment.newInstance(game) -            supportFragmentManager.beginTransaction() -                .add(R.id.frame_emulation_fragment, emulationFragment!!) -                .commit() -        } -        title = game.title -          nfcReader = NfcReader(this)          nfcReader.initialize()          inputHandler = InputHandler()          inputHandler.initialize() -        lifecycleScope.launch(Dispatchers.Main) { -            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { -                WindowInfoTracker.getOrCreate(this@EmulationActivity) -                    .windowLayoutInfo(this@EmulationActivity) -                    .collect { emulationFragment?.updateCurrentLayout(this@EmulationActivity, it) } -            } -        } -          // Start a foreground service to prevent the app from getting killed in the background          val startIntent = Intent(this, ForegroundService::class.java)          startForegroundService(startIntent) @@ -157,11 +134,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {          nfcReader.onNewIntent(intent)      } -    override fun onSaveInstanceState(outState: Bundle) { -        outState.putParcelable(EXTRA_SELECTED_GAME, game) -        super.onSaveInstanceState(outState) -    } -      override fun dispatchKeyEvent(event: KeyEvent): Boolean {          if (event.source and InputDevice.SOURCE_JOYSTICK != InputDevice.SOURCE_JOYSTICK &&              event.source and InputDevice.SOURCE_GAMEPAD != InputDevice.SOURCE_GAMEPAD @@ -248,10 +220,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {      override fun onAccuracyChanged(sensor: Sensor, i: Int) {} -    private fun restoreState(savedInstanceState: Bundle) { -        game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!! -    } -      private fun enableFullscreenImmersive() {          WindowCompat.setDecorFitsSystemWindows(window, false) diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index 7f9e2e2d4..83d08841b 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt @@ -16,6 +16,7 @@ import androidx.appcompat.app.AppCompatActivity  import androidx.documentfile.provider.DocumentFile  import androidx.lifecycle.ViewModelProvider  import androidx.lifecycle.lifecycleScope +import androidx.navigation.findNavController  import androidx.preference.PreferenceManager  import androidx.recyclerview.widget.AsyncDifferConfig  import androidx.recyclerview.widget.DiffUtil @@ -23,6 +24,7 @@ import androidx.recyclerview.widget.ListAdapter  import androidx.recyclerview.widget.RecyclerView  import coil.load  import kotlinx.coroutines.launch +import org.yuzu.yuzu_emu.HomeNavigationDirections  import org.yuzu.yuzu_emu.NativeLibrary  import org.yuzu.yuzu_emu.R  import org.yuzu.yuzu_emu.YuzuApplication @@ -78,7 +80,8 @@ class GameAdapter(private val activity: AppCompatActivity) :              )              .apply() -        EmulationActivity.launch(activity, holder.game) +        val action = HomeNavigationDirections.actionGlobalEmulationActivity(holder.game) +        view.findNavController().navigate(action)      }      inner class GameViewHolder(val binding: CardGameBinding) : 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 9523381cd..02bfcdb1e 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 @@ -26,11 +26,18 @@ import androidx.core.view.ViewCompat  import androidx.core.view.WindowInsetsCompat  import androidx.core.view.updatePadding  import androidx.fragment.app.Fragment +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.lifecycleScope +import androidx.lifecycle.repeatOnLifecycle +import androidx.navigation.fragment.navArgs  import androidx.preference.PreferenceManager  import androidx.window.layout.FoldingFeature +import androidx.window.layout.WindowInfoTracker  import androidx.window.layout.WindowLayoutInfo  import com.google.android.material.dialog.MaterialAlertDialogBuilder  import com.google.android.material.slider.Slider +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch  import org.yuzu.yuzu_emu.NativeLibrary  import org.yuzu.yuzu_emu.R  import org.yuzu.yuzu_emu.YuzuApplication @@ -41,9 +48,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.model.Game  import org.yuzu.yuzu_emu.utils.* -import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable  class EmulationFragment : Fragment(), SurfaceHolder.Callback {      private lateinit var preferences: SharedPreferences @@ -54,7 +59,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {      private var _binding: FragmentEmulationBinding? = null      private val binding get() = _binding!! -    private lateinit var game: Game +    val args by navArgs<EmulationFragmentArgs>()      override fun onAttach(context: Context) {          super.onAttach(context) @@ -75,8 +80,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {          // So this fragment doesn't restart on configuration changes; i.e. rotation.          retainInstance = true          preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) -        game = requireArguments().parcelable(EmulationActivity.EXTRA_SELECTED_GAME)!! -        emulationState = EmulationState(game.path) +        emulationState = EmulationState(args.game.path)      }      /** @@ -100,7 +104,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {          updateShowFpsOverlay()          binding.inGameMenu.getHeaderView(0).findViewById<TextView>(R.id.text_game_title).text = -            game.title +            args.game.title          binding.inGameMenu.setNavigationItemSelectedListener {              when (it.itemId) {                  R.id.menu_pause_emulation -> { @@ -153,6 +157,14 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {                      if (binding.drawerLayout.isOpen) binding.drawerLayout.close() else binding.drawerLayout.open()                  }              }) + +        viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) { +            lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { +                WindowInfoTracker.getOrCreate(requireContext()) +                    .windowLayoutInfo(requireActivity()) +                    .collect { updateCurrentLayout(requireActivity() as EmulationActivity, it) } +            } +        }      }      override fun onResume() { @@ -601,13 +613,5 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {      companion object {          private val perfStatsUpdateHandler = Handler(Looper.myLooper()!!) - -        fun newInstance(game: Game): EmulationFragment { -            val args = Bundle() -            args.putParcelable(EmulationActivity.EXTRA_SELECTED_GAME, game) -            val fragment = EmulationFragment() -            fragment.arguments = args -            return fragment -        }      }  } diff --git a/src/android/app/src/main/res/layout/activity_emulation.xml b/src/android/app/src/main/res/layout/activity_emulation.xml index f6360a65b..139065d3d 100644 --- a/src/android/app/src/main/res/layout/activity_emulation.xml +++ b/src/android/app/src/main/res/layout/activity_emulation.xml @@ -1,13 +1,9 @@ -<FrameLayout +<androidx.fragment.app.FragmentContainerView      xmlns:android="http://schemas.android.com/apk/res/android" -    android:id="@+id/frame_content" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    android:id="@+id/fragment_container" +    android:name="androidx.navigation.fragment.NavHostFragment"      android:layout_width="match_parent"      android:layout_height="match_parent" -    android:keepScreenOn="true"> - -    <FrameLayout -        android:id="@+id/frame_emulation_fragment" -        android:layout_width="match_parent" -        android:layout_height="match_parent" /> - -</FrameLayout> +    android:keepScreenOn="true" +    app:defaultNavHost="true" /> diff --git a/src/android/app/src/main/res/navigation/emulation_navigation.xml b/src/android/app/src/main/res/navigation/emulation_navigation.xml new file mode 100644 index 000000000..8208f4c2c --- /dev/null +++ b/src/android/app/src/main/res/navigation/emulation_navigation.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<navigation xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:app="http://schemas.android.com/apk/res-auto" +    xmlns:tools="http://schemas.android.com/tools" +    android:id="@+id/emulation_navigation" +    app:startDestination="@id/emulationFragment"> + +    <fragment +        android:id="@+id/emulationFragment" +        android:name="org.yuzu.yuzu_emu.fragments.EmulationFragment" +        android:label="fragment_emulation" +        tools:layout="@layout/fragment_emulation" > +        <argument +            android:name="game" +            app:argType="org.yuzu.yuzu_emu.model.Game" /> +    </fragment> + +</navigation> diff --git a/src/android/app/src/main/res/navigation/home_navigation.xml b/src/android/app/src/main/res/navigation/home_navigation.xml index 48072683e..fcebba726 100644 --- a/src/android/app/src/main/res/navigation/home_navigation.xml +++ b/src/android/app/src/main/res/navigation/home_navigation.xml @@ -56,4 +56,18 @@          android:name="org.yuzu.yuzu_emu.fragments.LicensesFragment"          android:label="LicensesFragment" /> +    <activity +        android:id="@+id/emulationActivity" +        android:name="org.yuzu.yuzu_emu.activities.EmulationActivity" +        android:label="EmulationActivity"> +        <argument +            android:name="game" +            app:argType="org.yuzu.yuzu_emu.model.Game" /> +    </activity> + +    <action +        android:id="@+id/action_global_emulationActivity" +        app:destination="@id/emulationActivity" +        app:launchSingleTop="true" /> +  </navigation> diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts index e19e8ce58..80f370c16 100644 --- a/src/android/build.gradle.kts +++ b/src/android/build.gradle.kts @@ -11,3 +11,12 @@ plugins {  tasks.register("clean").configure {      delete(rootProject.buildDir)  } + +buildscript { +    repositories { +        google() +    } +    dependencies { +        classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.6.0") +    } +} | 
