Android: Destroy the surface in EmulationFragment onStop.
Emulation needs to be running when the surface is destroyed, but we want to pause in onStop. So call the surfaceDestroyed callback, as this accomplished both.
This commit is contained in:
parent
987d24fe87
commit
18cb68eb3c
|
@ -275,8 +275,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
mImageView.setVisibility(View.GONE);
|
mImageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mEmulationFragment.startEmulation();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,14 +25,9 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
|
|
||||||
private SharedPreferences mPreferences;
|
private SharedPreferences mPreferences;
|
||||||
|
|
||||||
private Surface mSurface;
|
|
||||||
|
|
||||||
private InputOverlay mInputOverlay;
|
private InputOverlay mInputOverlay;
|
||||||
|
|
||||||
private Thread mEmulationThread;
|
private EmulationState mEmulationState;
|
||||||
|
|
||||||
private String mGamePath;
|
|
||||||
private final EmulationState mEmulationState = new EmulationState();
|
|
||||||
|
|
||||||
public static EmulationFragment newInstance(String gamePath)
|
public static EmulationFragment newInstance(String gamePath)
|
||||||
{
|
{
|
||||||
|
@ -73,7 +68,8 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
|
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
||||||
|
|
||||||
mGamePath = getArguments().getString(KEY_GAMEPATH);
|
String gamePath = getArguments().getString(KEY_GAMEPATH);
|
||||||
|
mEmulationState = new EmulationState(gamePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -116,10 +112,17 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop()
|
public void onResume()
|
||||||
{
|
{
|
||||||
pauseEmulation();
|
super.onResume();
|
||||||
super.onStop();
|
mEmulationState.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause()
|
||||||
|
{
|
||||||
|
mEmulationState.pause();
|
||||||
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -158,100 +161,27 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder)
|
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
|
@Override
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
Log.debug("[EmulationFragment] Surface changed. Resolution: " + width + "x" + height);
|
||||||
|
mEmulationState.newSurface(holder.getSurface());
|
||||||
if (mEmulationState.isPaused())
|
|
||||||
{
|
|
||||||
NativeLibrary.UnPauseEmulation();
|
|
||||||
}
|
|
||||||
|
|
||||||
mSurface = holder.getSurface();
|
|
||||||
NativeLibrary.SurfaceChanged(mSurface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceDestroyed(SurfaceHolder holder)
|
public void surfaceDestroyed(SurfaceHolder holder)
|
||||||
{
|
{
|
||||||
Log.debug("[EmulationFragment] Surface destroyed.");
|
mEmulationState.clearSurface();
|
||||||
NativeLibrary.SurfaceDestroyed();
|
|
||||||
|
|
||||||
if (mEmulationState.isRunning())
|
|
||||||
{
|
|
||||||
pauseEmulation();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
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()
|
public void startConfiguringControls()
|
||||||
{
|
{
|
||||||
|
@ -277,42 +207,149 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
STOPPED, RUNNING, PAUSED
|
STOPPED, RUNNING, PAUSED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final String mGamePath;
|
||||||
|
private Thread mEmulationThread;
|
||||||
private State state;
|
private State state;
|
||||||
|
private Surface mSurface;
|
||||||
|
private boolean mRunWhenSurfaceIsValid;
|
||||||
|
|
||||||
EmulationState()
|
EmulationState(String gamePath)
|
||||||
{
|
{
|
||||||
|
mGamePath = gamePath;
|
||||||
// Starting state is stopped.
|
// Starting state is stopped.
|
||||||
state = State.STOPPED;
|
state = State.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isStopped()
|
// Getters for the current state
|
||||||
|
|
||||||
|
public synchronized boolean isStopped()
|
||||||
{
|
{
|
||||||
return state == State.STOPPED;
|
return state == State.STOPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRunning()
|
public synchronized boolean isPaused()
|
||||||
{
|
|
||||||
return state == State.RUNNING;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isPaused()
|
|
||||||
{
|
{
|
||||||
return state == State.PAUSED;
|
return state == State.PAUSED;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run()
|
public synchronized boolean isRunning()
|
||||||
{
|
{
|
||||||
state = State.RUNNING;
|
return state == State.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause()
|
// State changing methods
|
||||||
{
|
|
||||||
state = State.PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop()
|
public synchronized void stop()
|
||||||
|
{
|
||||||
|
if (state != State.STOPPED)
|
||||||
{
|
{
|
||||||
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue