yuzu-emu
/
yuzu-android
Archived
1
0
Fork 0

android: Adapt EmulationActivity to navigation component

This commit is contained in:
Charles Lombardo 2023-06-11 19:54:54 -04:00
parent 278336af63
commit b79c993328
9 changed files with 86 additions and 74 deletions

View File

@ -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")
}
/**

View File

@ -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">

View File

@ -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)

View File

@ -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) :

View File

@ -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
}
}
}

View File

@ -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" />

View File

@ -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>

View File

@ -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>

View File

@ -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")
}
}