summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCharles Lombardo <clombardo169@gmail.com>2023-03-08 16:41:29 +0100
committerbunnei <bunneidev@gmail.com>2023-06-03 09:05:38 +0200
commit66079923aee1b75bfd14c8a0600a2e5b90a62895 (patch)
tree03077e5456e808c31684067da20f330682e8b5b1
parentandroid: Convert SettingsFile to Kotlin (diff)
downloadyuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar.gz
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar.bz2
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar.lz
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar.xz
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.tar.zst
yuzu-66079923aee1b75bfd14c8a0600a2e5b90a62895.zip
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java375
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt348
2 files changed, 348 insertions, 375 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java
deleted file mode 100644
index 2a2b0f68b..000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.java
+++ /dev/null
@@ -1,375 +0,0 @@
-package org.yuzu.yuzu_emu.fragments;
-
-import android.content.Context;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.graphics.Color;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.view.Choreographer;
-import android.view.LayoutInflater;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.fragment.app.Fragment;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
-
-import org.yuzu.yuzu_emu.NativeLibrary;
-import org.yuzu.yuzu_emu.R;
-import org.yuzu.yuzu_emu.activities.EmulationActivity;
-import org.yuzu.yuzu_emu.overlay.InputOverlay;
-import org.yuzu.yuzu_emu.utils.DirectoryInitialization;
-import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState;
-import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver;
-import org.yuzu.yuzu_emu.utils.Log;
-
-public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback, Choreographer.FrameCallback {
- private static final String KEY_GAMEPATH = "gamepath";
-
- private static final Handler perfStatsUpdateHandler = new Handler();
-
- private SharedPreferences mPreferences;
-
- private InputOverlay mInputOverlay;
-
- private EmulationState mEmulationState;
-
- private DirectoryStateReceiver directoryStateReceiver;
-
- private EmulationActivity activity;
-
- private TextView mPerfStats;
-
- private Runnable perfStatsUpdater;
-
- public static EmulationFragment newInstance(String gamePath) {
- Bundle args = new Bundle();
- args.putString(KEY_GAMEPATH, gamePath);
-
- EmulationFragment fragment = new EmulationFragment();
- fragment.setArguments(args);
- return fragment;
- }
-
- @Override
- public void onAttach(@NonNull Context context) {
- super.onAttach(context);
-
- if (context instanceof EmulationActivity) {
- activity = (EmulationActivity) context;
- NativeLibrary.setEmulationActivity((EmulationActivity) context);
- } else {
- throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
- }
- }
-
- /**
- * Initialize anything that doesn't depend on the layout / views in here.
- */
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- // So this fragment doesn't restart on configuration changes; i.e. rotation.
- setRetainInstance(true);
-
- mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
-
- String gamePath = getArguments().getString(KEY_GAMEPATH);
- mEmulationState = new EmulationState(gamePath);
- }
-
- /**
- * Initialize the UI and start emulation in here.
- */
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
-
- SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
- surfaceView.getHolder().addCallback(this);
-
- mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
- mPerfStats = contents.findViewById(R.id.show_fps_text);
- mPerfStats.setTextColor(Color.YELLOW);
-
- Button doneButton = contents.findViewById(R.id.done_control_config);
- if (doneButton != null) {
- doneButton.setOnClickListener(v -> stopConfiguringControls());
- }
-
- // Setup overlay.
- resetInputOverlay();
- updateShowFpsOverlay();
-
- // The new Surface created here will get passed to the native code via onSurfaceChanged.
- return contents;
- }
-
- @Override
- public void onResume() {
- super.onResume();
- Choreographer.getInstance().postFrameCallback(this);
- if (DirectoryInitialization.areDirectoriesReady()) {
- mEmulationState.run(activity.isActivityRecreated());
- } else {
- setupDirectoriesThenStartEmulation();
- }
- }
-
- @Override
- public void onPause() {
- if (directoryStateReceiver != null) {
- LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(directoryStateReceiver);
- directoryStateReceiver = null;
- }
-
- if (mEmulationState.isRunning()) {
- mEmulationState.pause();
- }
-
- Choreographer.getInstance().removeFrameCallback(this);
- super.onPause();
- }
-
- @Override
- public void onDetach() {
- NativeLibrary.clearEmulationActivity();
- super.onDetach();
- }
-
- private void setupDirectoriesThenStartEmulation() {
- IntentFilter statusIntentFilter = new IntentFilter(
- DirectoryInitialization.BROADCAST_ACTION);
-
- directoryStateReceiver =
- new DirectoryStateReceiver(directoryInitializationState ->
- {
- if (directoryInitializationState ==
- DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED) {
- mEmulationState.run(activity.isActivityRecreated());
- } else if (directoryInitializationState ==
- DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE) {
- Toast.makeText(getContext(), R.string.external_storage_not_mounted,
- Toast.LENGTH_SHORT)
- .show();
- }
- });
-
- // Registers the DirectoryStateReceiver and its intent filters
- LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
- directoryStateReceiver,
- statusIntentFilter);
- DirectoryInitialization.start(getActivity());
- }
-
- public void refreshInputOverlay() {
- mInputOverlay.refreshControls();
- }
-
- public void resetInputOverlay() {
- // Reset button scale
- SharedPreferences.Editor editor = mPreferences.edit();
- editor.putInt("controlScale", 50);
- editor.apply();
-
- mInputOverlay.resetButtonPlacement();
- }
-
- public void updateShowFpsOverlay() {
- if (true) {
- final int SYSTEM_FPS = 0;
- final int FPS = 1;
- final int FRAMETIME = 2;
- final int SPEED = 3;
-
- perfStatsUpdater = () ->
- {
- final double[] perfStats = NativeLibrary.GetPerfStats();
- if (perfStats[FPS] > 0) {
- mPerfStats.setText(String.format("FPS: %.1f", perfStats[FPS]));
- }
-
- perfStatsUpdateHandler.postDelayed(perfStatsUpdater, 100);
- };
- perfStatsUpdateHandler.post(perfStatsUpdater);
-
- mPerfStats.setVisibility(View.VISIBLE);
- } else {
- if (perfStatsUpdater != null) {
- perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater);
- }
-
- mPerfStats.setVisibility(View.GONE);
- }
- }
-
- @Override
- public void surfaceCreated(SurfaceHolder holder) {
- // We purposely don't do anything here.
- // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
- }
-
- @Override
- public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
- Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
- mEmulationState.newSurface(holder.getSurface());
- }
-
- @Override
- public void surfaceDestroyed(SurfaceHolder holder) {
- mEmulationState.clearSurface();
- }
-
- @Override
- public void doFrame(long frameTimeNanos) {
- Choreographer.getInstance().postFrameCallback(this);
- NativeLibrary.DoFrame();
- }
-
- public void stopEmulation() {
- mEmulationState.stop();
- }
-
- public void startConfiguringControls() {
- getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
- mInputOverlay.setIsInEditMode(true);
- }
-
- public void stopConfiguringControls() {
- getView().findViewById(R.id.done_control_config).setVisibility(View.GONE);
- mInputOverlay.setIsInEditMode(false);
- }
-
- public boolean isConfiguringControls() {
- return mInputOverlay.isInEditMode();
- }
-
- private static class EmulationState {
- private final String mGamePath;
- private State state;
- private Surface mSurface;
- private boolean mRunWhenSurfaceIsValid;
-
- EmulationState(String gamePath) {
- mGamePath = gamePath;
- // Starting state is stopped.
- state = State.STOPPED;
- }
-
- public synchronized boolean isStopped() {
- return state == State.STOPPED;
- }
-
- // Getters for the current state
-
- public synchronized boolean isPaused() {
- return state == State.PAUSED;
- }
-
- public synchronized boolean isRunning() {
- return state == State.RUNNING;
- }
-
- public synchronized void stop() {
- if (state != State.STOPPED) {
- Log.debug("[EmulationFragment] Stopping emulation.");
- state = State.STOPPED;
- NativeLibrary.StopEmulation();
- } else {
- Log.warning("[EmulationFragment] Stop called while already stopped.");
- }
- }
-
- // State changing methods
-
- public synchronized void pause() {
- if (state != State.PAUSED) {
- state = State.PAUSED;
- Log.debug("[EmulationFragment] Pausing emulation.");
-
- // Release the surface before pausing, since emulation has to be running for that.
- NativeLibrary.SurfaceDestroyed();
- NativeLibrary.PauseEmulation();
- } else {
- Log.warning("[EmulationFragment] Pause called while already paused.");
- }
- }
-
- public synchronized void run(boolean isActivityRecreated) {
- if (isActivityRecreated) {
- if (NativeLibrary.IsRunning()) {
- state = State.PAUSED;
- }
- } else {
- Log.debug("[EmulationFragment] activity resumed or fresh start");
- }
-
- // If the surface is set, run now. Otherwise, wait for it to get set.
- if (mSurface != null) {
- runWithValidSurface();
- } else {
- mRunWhenSurfaceIsValid = true;
- }
- }
-
- // Surface callbacks
- public synchronized void newSurface(Surface surface) {
- mSurface = surface;
- if (mRunWhenSurfaceIsValid) {
- runWithValidSurface();
- }
- }
-
- public synchronized void clearSurface() {
- if (mSurface == null) {
- Log.warning("[EmulationFragment] clearSurface called, but surface already null.");
- } else {
- mSurface = null;
- Log.debug("[EmulationFragment] Surface destroyed.");
-
- if (state == State.RUNNING) {
- NativeLibrary.SurfaceDestroyed();
- state = State.PAUSED;
- } else if (state == State.PAUSED) {
- Log.warning("[EmulationFragment] Surface cleared while emulation paused.");
- } else {
- Log.warning("[EmulationFragment] Surface cleared while emulation stopped.");
- }
- }
- }
-
- private void runWithValidSurface() {
- mRunWhenSurfaceIsValid = false;
- if (state == State.STOPPED) {
- NativeLibrary.SurfaceChanged(mSurface);
- Thread mEmulationThread = new Thread(() ->
- {
- Log.debug("[EmulationFragment] Starting emulation thread.");
- NativeLibrary.Run(mGamePath);
- }, "NativeEmulation");
- mEmulationThread.start();
-
- } else if (state == State.PAUSED) {
- Log.debug("[EmulationFragment] Resuming emulation.");
- NativeLibrary.SurfaceChanged(mSurface);
- NativeLibrary.UnPauseEmulation();
- } else {
- Log.debug("[EmulationFragment] Bug, run called while already running.");
- }
- state = State.RUNNING;
- }
-
- private enum State {
- STOPPED, RUNNING, PAUSED
- }
- }
-}
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
new file mode 100644
index 000000000..77964b88c
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/EmulationFragment.kt
@@ -0,0 +1,348 @@
+package org.yuzu.yuzu_emu.fragments
+
+import android.content.Context
+import android.content.IntentFilter
+import android.content.SharedPreferences
+import android.graphics.Color
+import android.os.Bundle
+import android.os.Handler
+import android.view.*
+import android.widget.Button
+import android.widget.TextView
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.localbroadcastmanager.content.LocalBroadcastManager
+import androidx.preference.PreferenceManager
+import org.yuzu.yuzu_emu.NativeLibrary
+import org.yuzu.yuzu_emu.R
+import org.yuzu.yuzu_emu.YuzuApplication
+import org.yuzu.yuzu_emu.activities.EmulationActivity
+import org.yuzu.yuzu_emu.features.settings.model.Settings
+import org.yuzu.yuzu_emu.overlay.InputOverlay
+import org.yuzu.yuzu_emu.utils.DirectoryInitialization
+import org.yuzu.yuzu_emu.utils.DirectoryInitialization.DirectoryInitializationState
+import org.yuzu.yuzu_emu.utils.DirectoryStateReceiver
+import org.yuzu.yuzu_emu.utils.Log
+
+class EmulationFragment : Fragment(), SurfaceHolder.Callback, Choreographer.FrameCallback {
+ private lateinit var preferences: SharedPreferences
+ private var inputOverlay: InputOverlay? = null
+ private lateinit var emulationState: EmulationState
+ private var directoryStateReceiver: DirectoryStateReceiver? = null
+ private var emulationActivity: EmulationActivity? = null
+ private lateinit var perfStats: TextView
+ private var perfStatsUpdater: (() -> Unit)? = null
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ if (context is EmulationActivity) {
+ emulationActivity = context
+ NativeLibrary.setEmulationActivity(context)
+ } else {
+ throw IllegalStateException("EmulationFragment must have EmulationActivity parent")
+ }
+ }
+
+ /**
+ * Initialize anything that doesn't depend on the layout / views in here.
+ */
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ // So this fragment doesn't restart on configuration changes; i.e. rotation.
+ retainInstance = true
+ preferences = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
+ val gamePath = requireArguments().getString(KEY_GAMEPATH)
+ emulationState = EmulationState(gamePath)
+ }
+
+ /**
+ * Initialize the UI and start emulation in here.
+ */
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val contents = inflater.inflate(R.layout.fragment_emulation, container, false)
+ val surfaceView = contents.findViewById<SurfaceView>(R.id.surface_emulation)
+ surfaceView.holder.addCallback(this)
+ inputOverlay = contents.findViewById(R.id.surface_input_overlay)
+ perfStats = contents.findViewById(R.id.show_fps_text)
+ perfStats.setTextColor(Color.YELLOW)
+ val doneButton = contents.findViewById<Button>(R.id.done_control_config)
+ doneButton?.setOnClickListener { stopConfiguringControls() }
+
+ // Setup overlay.
+ resetInputOverlay()
+ updateShowFpsOverlay()
+
+ // The new Surface created here will get passed to the native code via onSurfaceChanged.
+ return contents
+ }
+
+ override fun onResume() {
+ super.onResume()
+ Choreographer.getInstance().postFrameCallback(this)
+ if (DirectoryInitialization.areDirectoriesReady()) {
+ emulationState.run(emulationActivity!!.isActivityRecreated)
+ } else {
+ setupDirectoriesThenStartEmulation()
+ }
+ }
+
+ override fun onPause() {
+ if (directoryStateReceiver != null) {
+ LocalBroadcastManager.getInstance(requireActivity()).unregisterReceiver(
+ directoryStateReceiver!!
+ )
+ directoryStateReceiver = null
+ }
+ if (emulationState.isRunning) {
+ emulationState.pause()
+ }
+ Choreographer.getInstance().removeFrameCallback(this)
+ super.onPause()
+ }
+
+ override fun onDetach() {
+ NativeLibrary.clearEmulationActivity()
+ super.onDetach()
+ }
+
+ private fun setupDirectoriesThenStartEmulation() {
+ val statusIntentFilter = IntentFilter(
+ DirectoryInitialization.BROADCAST_ACTION
+ )
+ directoryStateReceiver =
+ DirectoryStateReceiver { directoryInitializationState: DirectoryInitializationState ->
+ if (directoryInitializationState ==
+ DirectoryInitializationState.YUZU_DIRECTORIES_INITIALIZED
+ ) {
+ emulationState.run(emulationActivity!!.isActivityRecreated)
+ } else if (directoryInitializationState ==
+ DirectoryInitializationState.CANT_FIND_EXTERNAL_STORAGE
+ ) {
+ Toast.makeText(
+ context,
+ R.string.external_storage_not_mounted,
+ Toast.LENGTH_SHORT
+ )
+ .show()
+ }
+ }
+
+ // Registers the DirectoryStateReceiver and its intent filters
+ LocalBroadcastManager.getInstance(requireActivity()).registerReceiver(
+ directoryStateReceiver!!,
+ statusIntentFilter
+ )
+ DirectoryInitialization.start(requireContext())
+ }
+
+ fun refreshInputOverlay() {
+ inputOverlay!!.refreshControls()
+ }
+
+ fun resetInputOverlay() {
+ // Reset button scale
+ preferences.edit()
+ .putInt(Settings.PREF_CONTROL_SCALE, 50)
+ .apply()
+ inputOverlay!!.resetButtonPlacement()
+ }
+
+ private fun updateShowFpsOverlay() {
+ // TODO: Create a setting so that this actually works...
+ if (true) {
+ val SYSTEM_FPS = 0
+ val FPS = 1
+ val FRAMETIME = 2
+ val SPEED = 3
+ perfStatsUpdater = {
+ val perfStats = NativeLibrary.GetPerfStats()
+ if (perfStats[FPS] > 0) {
+ this.perfStats.text = String.format("FPS: %.1f", perfStats[FPS])
+ }
+ perfStatsUpdateHandler.postDelayed(perfStatsUpdater!!, 100)
+ }
+ perfStatsUpdateHandler.post(perfStatsUpdater!!)
+ perfStats.visibility = View.VISIBLE
+ } else {
+ if (perfStatsUpdater != null) {
+ perfStatsUpdateHandler.removeCallbacks(perfStatsUpdater!!)
+ }
+ perfStats.visibility = View.GONE
+ }
+ }
+
+ override fun surfaceCreated(holder: SurfaceHolder) {
+ // We purposely don't do anything here.
+ // All work is done in surfaceChanged, which we are guaranteed to get even for surface creation.
+ }
+
+ override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
+ Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height)
+ emulationState.newSurface(holder.surface)
+ }
+
+ override fun surfaceDestroyed(holder: SurfaceHolder) {
+ emulationState.clearSurface()
+ }
+
+ override fun doFrame(frameTimeNanos: Long) {
+ Choreographer.getInstance().postFrameCallback(this)
+ NativeLibrary.DoFrame()
+ }
+
+ fun stopEmulation() {
+ emulationState.stop()
+ }
+
+ fun startConfiguringControls() {
+ requireView().findViewById<View>(R.id.done_control_config).visibility =
+ View.VISIBLE
+ inputOverlay!!.setIsInEditMode(true)
+ }
+
+ fun stopConfiguringControls() {
+ requireView().findViewById<View>(R.id.done_control_config).visibility = View.GONE
+ inputOverlay!!.setIsInEditMode(false)
+ }
+
+ val isConfiguringControls: Boolean
+ get() = inputOverlay!!.isInEditMode
+
+ private class EmulationState(private val mGamePath: String?) {
+ private var state: State
+ private var surface: Surface? = null
+ private var runWhenSurfaceIsValid = false
+
+ init {
+ // Starting state is stopped.
+ state = State.STOPPED
+ }
+
+ @get:Synchronized
+ val isStopped: Boolean
+ get() = state == State.STOPPED
+
+ // Getters for the current state
+ @get:Synchronized
+ val isPaused: Boolean
+ get() = state == State.PAUSED
+
+ @get:Synchronized
+ val isRunning: Boolean
+ get() = state == State.RUNNING
+
+ @Synchronized
+ fun stop() {
+ if (state != State.STOPPED) {
+ Log.debug("[EmulationFragment] Stopping emulation.")
+ state = State.STOPPED
+ NativeLibrary.StopEmulation()
+ } else {
+ Log.warning("[EmulationFragment] Stop called while already stopped.")
+ }
+ }
+
+ // State changing methods
+ @Synchronized
+ fun pause() {
+ if (state != State.PAUSED) {
+ state = State.PAUSED
+ Log.debug("[EmulationFragment] Pausing emulation.")
+
+ // Release the surface before pausing, since emulation has to be running for that.
+ NativeLibrary.SurfaceDestroyed()
+ NativeLibrary.PauseEmulation()
+ } else {
+ Log.warning("[EmulationFragment] Pause called while already paused.")
+ }
+ }
+
+ @Synchronized
+ fun run(isActivityRecreated: Boolean) {
+ if (isActivityRecreated) {
+ if (NativeLibrary.IsRunning()) {
+ state = State.PAUSED
+ }
+ } else {
+ Log.debug("[EmulationFragment] activity resumed or fresh start")
+ }
+
+ // If the surface is set, run now. Otherwise, wait for it to get set.
+ if (surface != null) {
+ runWithValidSurface()
+ } else {
+ runWhenSurfaceIsValid = true
+ }
+ }
+
+ // Surface callbacks
+ @Synchronized
+ fun newSurface(surface: Surface?) {
+ this.surface = surface
+ if (runWhenSurfaceIsValid) {
+ runWithValidSurface()
+ }
+ }
+
+ @Synchronized
+ fun clearSurface() {
+ if (surface == null) {
+ Log.warning("[EmulationFragment] clearSurface called, but surface already null.")
+ } else {
+ surface = null
+ Log.debug("[EmulationFragment] Surface destroyed.")
+ when (state) {
+ State.RUNNING -> {
+ NativeLibrary.SurfaceDestroyed()
+ state = State.PAUSED
+ }
+ State.PAUSED -> Log.warning("[EmulationFragment] Surface cleared while emulation paused.")
+ else -> Log.warning("[EmulationFragment] Surface cleared while emulation stopped.")
+ }
+ }
+ }
+
+ private fun runWithValidSurface() {
+ runWhenSurfaceIsValid = false
+ when (state) {
+ State.STOPPED -> {
+ NativeLibrary.SurfaceChanged(surface)
+ val mEmulationThread = Thread({
+ Log.debug("[EmulationFragment] Starting emulation thread.")
+ NativeLibrary.Run(mGamePath)
+ }, "NativeEmulation")
+ mEmulationThread.start()
+ }
+ State.PAUSED -> {
+ Log.debug("[EmulationFragment] Resuming emulation.")
+ NativeLibrary.SurfaceChanged(surface)
+ NativeLibrary.UnPauseEmulation()
+ }
+ else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
+ }
+ state = State.RUNNING
+ }
+
+ private enum class State {
+ STOPPED, RUNNING, PAUSED
+ }
+ }
+
+ companion object {
+ private const val KEY_GAMEPATH = "gamepath"
+ private val perfStatsUpdateHandler = Handler()
+
+ fun newInstance(gamePath: String?): EmulationFragment {
+ val args = Bundle()
+ args.putString(KEY_GAMEPATH, gamePath)
+ val fragment = EmulationFragment()
+ fragment.arguments = args
+ return fragment
+ }
+ }
+}