Merge pull request #6139 from hackbar/rotation-fix
Android: Destroy the surface in EmulationFragment onStop.
This commit is contained in:
commit
20a02a9765
|
@ -42,6 +42,7 @@ import org.dolphinemu.dolphinemu.ui.platform.Platform;
|
|||
import org.dolphinemu.dolphinemu.utils.Animations;
|
||||
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
||||
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
||||
import org.dolphinemu.dolphinemu.utils.Log;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.util.List;
|
||||
|
@ -226,8 +227,17 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
setContentView(R.layout.activity_emulation);
|
||||
|
||||
mImageView = (ImageView) findViewById(R.id.image_screenshot);
|
||||
|
||||
// Find or create the EmulationFragment
|
||||
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
||||
.findFragmentById(R.id.fragment_emulation);
|
||||
.findFragmentById(R.id.frame_emulation_fragment);
|
||||
if (mEmulationFragment == null)
|
||||
{
|
||||
mEmulationFragment = EmulationFragment.newInstance(path);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(R.id.frame_emulation_fragment, mEmulationFragment)
|
||||
.commit();
|
||||
}
|
||||
|
||||
if (savedInstanceState == null)
|
||||
{
|
||||
|
@ -265,9 +275,6 @@ public final class EmulationActivity extends AppCompatActivity
|
|||
mImageView.setVisibility(View.GONE);
|
||||
}
|
||||
});
|
||||
|
||||
mEmulationFragment.setGamePath(path);
|
||||
mEmulationFragment.startEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -21,16 +21,24 @@ import org.dolphinemu.dolphinemu.utils.Log;
|
|||
|
||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
||||
{
|
||||
private SharedPreferences mPreferences;
|
||||
private static final String KEY_GAMEPATH = "gamepath";
|
||||
|
||||
private Surface mSurface;
|
||||
private SharedPreferences mPreferences;
|
||||
|
||||
private InputOverlay mInputOverlay;
|
||||
|
||||
private Thread mEmulationThread;
|
||||
private EmulationState mEmulationState;
|
||||
|
||||
private String mGamePath;
|
||||
private final EmulationState mEmulationState = new EmulationState();
|
||||
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(Context context)
|
||||
|
@ -59,6 +67,9 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
setRetainInstance(true);
|
||||
|
||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||
|
||||
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
||||
mEmulationState = new EmulationState(gamePath);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,10 +112,17 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onStop()
|
||||
public void onResume()
|
||||
{
|
||||
pauseEmulation();
|
||||
super.onStop();
|
||||
super.onResume();
|
||||
mEmulationState.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
mEmulationState.pause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,11 +132,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
super.onDetach();
|
||||
}
|
||||
|
||||
public void setGamePath(String gamePath)
|
||||
{
|
||||
mGamePath = gamePath;
|
||||
}
|
||||
|
||||
public void toggleInputOverlayVisibility()
|
||||
{
|
||||
SharedPreferences.Editor editor = mPreferences.edit();
|
||||
|
@ -148,100 +161,27 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
@Override
|
||||
public void surfaceCreated(SurfaceHolder holder)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Surface created.");
|
||||
// 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);
|
||||
|
||||
if (mEmulationState.isPaused())
|
||||
{
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
}
|
||||
|
||||
mSurface = holder.getSurface();
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
mEmulationState.newSurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(SurfaceHolder holder)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
|
||||
if (mEmulationState.isRunning())
|
||||
{
|
||||
pauseEmulation();
|
||||
}
|
||||
mEmulationState.clearSurface();
|
||||
}
|
||||
|
||||
public void startEmulation()
|
||||
public void stopEmulation()
|
||||
{
|
||||
synchronized (mEmulationState)
|
||||
{
|
||||
if (mEmulationState.isStopped())
|
||||
{
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
||||
|
||||
mEmulationThread = new Thread(mEmulationRunner, "NativeEmulation");
|
||||
mEmulationThread.start();
|
||||
// The thread will call mEmulationState.run()
|
||||
}
|
||||
else if (mEmulationState.isPaused())
|
||||
{
|
||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
mEmulationState.run();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.debug("[EmulationFragment] Bug, startEmulation called while running.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopEmulation() {
|
||||
synchronized (mEmulationState)
|
||||
{
|
||||
if (!mEmulationState.isStopped())
|
||||
{
|
||||
NativeLibrary.StopEmulation();
|
||||
mEmulationState.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void pauseEmulation()
|
||||
{
|
||||
synchronized (mEmulationState)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Pausing emulation.");
|
||||
|
||||
NativeLibrary.PauseEmulation();
|
||||
mEmulationState.pause();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable mEmulationRunner = new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
// Busy-wait for surface to be set
|
||||
while (mSurface == null) {}
|
||||
|
||||
synchronized (mEmulationState)
|
||||
{
|
||||
Log.info("[EmulationFragment] Starting emulation: " + mSurface);
|
||||
|
||||
mEmulationState.run();
|
||||
}
|
||||
// Start emulation using the provided Surface.
|
||||
NativeLibrary.Run(mGamePath);
|
||||
}
|
||||
};
|
||||
|
||||
public void startConfiguringControls()
|
||||
{
|
||||
|
@ -267,42 +207,149 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
|||
STOPPED, RUNNING, PAUSED
|
||||
}
|
||||
|
||||
private final String mGamePath;
|
||||
private Thread mEmulationThread;
|
||||
private State state;
|
||||
private Surface mSurface;
|
||||
private boolean mRunWhenSurfaceIsValid;
|
||||
|
||||
EmulationState()
|
||||
EmulationState(String gamePath)
|
||||
{
|
||||
mGamePath = gamePath;
|
||||
// Starting state is stopped.
|
||||
state = State.STOPPED;
|
||||
}
|
||||
|
||||
public boolean isStopped()
|
||||
// Getters for the current state
|
||||
|
||||
public synchronized boolean isStopped()
|
||||
{
|
||||
return state == State.STOPPED;
|
||||
}
|
||||
|
||||
public boolean isRunning()
|
||||
{
|
||||
return state == State.RUNNING;
|
||||
}
|
||||
|
||||
public boolean isPaused()
|
||||
public synchronized boolean isPaused()
|
||||
{
|
||||
return state == State.PAUSED;
|
||||
}
|
||||
|
||||
public void run()
|
||||
public synchronized boolean isRunning()
|
||||
{
|
||||
state = State.RUNNING;
|
||||
return state == State.RUNNING;
|
||||
}
|
||||
|
||||
public void pause()
|
||||
{
|
||||
state = State.PAUSED;
|
||||
}
|
||||
// State changing methods
|
||||
|
||||
public void stop()
|
||||
public synchronized void stop()
|
||||
{
|
||||
if (state != State.STOPPED)
|
||||
{
|
||||
state = State.STOPPED;
|
||||
NativeLibrary.StopEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("[EmulationFragment] Stop called while already stopped.");
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
mSurface = null;
|
||||
NativeLibrary.SurfaceDestroyed();
|
||||
NativeLibrary.PauseEmulation();
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.warning("[EmulationFragment] Pause called while already paused.");
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void run()
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Starting emulation thread.");
|
||||
|
||||
mEmulationThread = new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
NativeLibrary.Run(mGamePath);
|
||||
}},
|
||||
"NativeEmulation");
|
||||
mEmulationThread.start();
|
||||
|
||||
}
|
||||
else if (state == State.PAUSED)
|
||||
{
|
||||
Log.debug("[EmulationFragment] Resuming emulation.");
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
NativeLibrary.SurfaceChanged(mSurface);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.debug("[EmulationFragment] Bug, run called while already running.");
|
||||
}
|
||||
state = State.RUNNING;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,8 @@
|
|||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/frame_content">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment_emulation"
|
||||
android:name="org.dolphinemu.dolphinemu.fragments.EmulationFragment"
|
||||
<FrameLayout
|
||||
android:id="@+id/frame_emulation_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
|
|
@ -3,9 +3,8 @@
|
|||
android:layout_height="match_parent"
|
||||
android:id="@+id/frame_content">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/fragment_emulation"
|
||||
android:name="org.dolphinemu.dolphinemu.fragments.EmulationFragment"
|
||||
<FrameLayout
|
||||
android:id="@+id/frame_emulation_fragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
|
|
Loading…
Reference in New Issue