diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java index 7c83c9d977..4b3adf10c6 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.java @@ -4,7 +4,11 @@ import android.app.Fragment; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; +import android.util.Log; import android.view.LayoutInflater; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceView; import android.view.View; import android.view.ViewGroup; @@ -14,7 +18,7 @@ import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.emulation.overlay.InputOverlay; -public final class EmulationFragment extends Fragment +public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback { public static final String FRAGMENT_TAG = BuildConfig.APPLICATION_ID + ".emulation_fragment"; @@ -22,8 +26,19 @@ public final class EmulationFragment extends Fragment private SharedPreferences mPreferences; + private SurfaceView mSurfaceView; + private Surface mSurface; + private InputOverlay mInputOverlay; + private Thread mEmulationThread; + + private String mPath; + + private boolean mEmulationStarted; + private boolean mEmulationRunning; + + public static EmulationFragment newInstance(String path) { EmulationFragment fragment = new EmulationFragment(); @@ -43,6 +58,9 @@ public final class EmulationFragment extends Fragment { super.onCreate(savedInstanceState); + // So this fragment doesn't restart on configuration changes; i.e. rotation. + setRetainInstance(true); + mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity()); } @@ -52,14 +70,15 @@ public final class EmulationFragment extends Fragment @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - String path = getArguments().getString(ARGUMENT_GAME_PATH); + mPath = getArguments().getString(ARGUMENT_GAME_PATH); + NativeLibrary.SetFilename(mPath); View contents = inflater.inflate(R.layout.fragment_emulation, container, false); + mSurfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation); mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay); - NativeLibrary.SetFilename(path); - + mSurfaceView.getHolder().addCallback(this); // If the input overlay was previously disabled, then don't show it. if (!mPreferences.getBoolean("showInputOverlay", true)) @@ -67,6 +86,18 @@ public final class EmulationFragment extends Fragment mInputOverlay.setVisibility(View.GONE); } + + if (savedInstanceState == null) + { + mEmulationThread = new Thread(mEmulationRunner); + } + else + { + // Likely a rotation occurred. + // TODO Pass native code the Surface, which will have been recreated, from surfaceChanged() + // TODO Also, write the native code that will get the video backend to accept the new Surface as one of its own. + } + return contents; } @@ -74,21 +105,24 @@ public final class EmulationFragment extends Fragment public void onStart() { super.onStart(); - NativeLibrary.UnPauseEmulation(); + startEmulation(); } @Override public void onStop() { super.onStop(); - NativeLibrary.PauseEmulation(); + pauseEmulation(); } @Override public void onDestroyView() { super.onDestroyView(); - NativeLibrary.StopEmulation(); + if (getActivity().isFinishing()) + { + NativeLibrary.StopEmulation(); + } } public void toggleInputOverlayVisibility() @@ -111,4 +145,78 @@ public final class EmulationFragment extends Fragment editor.apply(); } + + @Override + public void surfaceCreated(SurfaceHolder holder) + { + Log.d("DolphinEmu", "Surface created."); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) + { + Log.d("DolphinEmu", "Surface changed. Resolution: " + width + "x" + height); + mSurface = holder.getSurface(); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) + { + Log.d("DolphinEmu", "Surface destroyed."); + + if (mEmulationRunning) + { + pauseEmulation(); + } + } + + private void startEmulation() + { + if (!mEmulationStarted) + { + Log.d("DolphinEmu", "Starting emulation thread."); + + mEmulationThread.start(); + } + else + { + Log.d("DolphinEmu", "Resuming emulation."); + NativeLibrary.UnPauseEmulation(); + } + + mEmulationRunning = true; + } + + private void pauseEmulation() + { + Log.d("DolphinEmu", "Pausing emulation."); + + NativeLibrary.PauseEmulation(); + mEmulationRunning = false; + } + + private Runnable mEmulationRunner = new Runnable() + { + @Override + public void run() + { + mEmulationRunning = true; + mEmulationStarted = true; + + // Loop until onSurfaceCreated succeeds + while (mSurface == null) + { + if (!mEmulationRunning) + { + // So that if the user quits before this gets a surface, we don't loop infinitely. + return; + } + } + + Log.i("DolphinEmu", "Starting emulation: " + mSurface); + + // Start emulation using the provided Surface. + NativeLibrary.Run(mSurface); + } + }; } diff --git a/Source/Android/app/src/main/res/layout/fragment_emulation.xml b/Source/Android/app/src/main/res/layout/fragment_emulation.xml index 6a936dae64..1db0d6b49f 100644 --- a/Source/Android/app/src/main/res/layout/fragment_emulation.xml +++ b/Source/Android/app/src/main/res/layout/fragment_emulation.xml @@ -5,7 +5,7 @@ tools:context="org.dolphinemu.dolphinemu.fragments.EmulationFragment"> -