android: Adapt EmulationActivity to navigation component
This commit is contained in:
		| @@ -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") | ||||
| } | ||||
|  | ||||
| /** | ||||
|   | ||||
| @@ -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"> | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|  | ||||
|   | ||||
| @@ -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) : | ||||
|   | ||||
| @@ -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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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" /> | ||||
|   | ||||
| @@ -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> | ||||
| @@ -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> | ||||
|   | ||||
| @@ -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") | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user