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.Animations;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_GCAdapter;
|
||||||
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
import org.dolphinemu.dolphinemu.utils.Java_WiimoteAdapter;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -226,8 +227,17 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
setContentView(R.layout.activity_emulation);
|
setContentView(R.layout.activity_emulation);
|
||||||
|
|
||||||
mImageView = (ImageView) findViewById(R.id.image_screenshot);
|
mImageView = (ImageView) findViewById(R.id.image_screenshot);
|
||||||
|
|
||||||
|
// Find or create the EmulationFragment
|
||||||
mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
|
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)
|
if (savedInstanceState == null)
|
||||||
{
|
{
|
||||||
|
@ -265,9 +275,6 @@ public final class EmulationActivity extends AppCompatActivity
|
||||||
mImageView.setVisibility(View.GONE);
|
mImageView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
mEmulationFragment.setGamePath(path);
|
|
||||||
mEmulationFragment.startEmulation();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,16 +21,24 @@ import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
|
|
||||||
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
|
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 InputOverlay mInputOverlay;
|
||||||
|
|
||||||
private Thread mEmulationThread;
|
private EmulationState mEmulationState;
|
||||||
|
|
||||||
private String mGamePath;
|
public static EmulationFragment newInstance(String gamePath)
|
||||||
private final EmulationState mEmulationState = new EmulationState();
|
{
|
||||||
|
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(KEY_GAMEPATH, gamePath);
|
||||||
|
|
||||||
|
EmulationFragment fragment = new EmulationFragment();
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onAttach(Context context)
|
public void onAttach(Context context)
|
||||||
|
@ -59,6 +67,9 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
setRetainInstance(true);
|
setRetainInstance(true);
|
||||||
|
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
|
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
|
@Override
|
||||||
public void onStop()
|
public void onResume()
|
||||||
{
|
{
|
||||||
pauseEmulation();
|
super.onResume();
|
||||||
super.onStop();
|
mEmulationState.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPause()
|
||||||
|
{
|
||||||
|
mEmulationState.pause();
|
||||||
|
super.onPause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -114,11 +132,6 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
|
||||||
super.onDetach();
|
super.onDetach();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGamePath(String gamePath)
|
|
||||||
{
|
|
||||||
mGamePath = gamePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void toggleInputOverlayVisibility()
|
public void toggleInputOverlayVisibility()
|
||||||
{
|
{
|
||||||
SharedPreferences.Editor editor = mPreferences.edit();
|
SharedPreferences.Editor editor = mPreferences.edit();
|
||||||
|
@ -148,101 +161,28 @@ 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)
|
mEmulationState.stop();
|
||||||
{
|
|
||||||
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()
|
public void startConfiguringControls()
|
||||||
{
|
{
|
||||||
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
getView().findViewById(R.id.done_control_config).setVisibility(View.VISIBLE);
|
||||||
|
@ -267,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()
|
||||||
{
|
{
|
||||||
|
return state == State.RUNNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
// State changing methods
|
||||||
|
|
||||||
|
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;
|
state = State.RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void pause()
|
|
||||||
{
|
|
||||||
state = State.PAUSED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop()
|
|
||||||
{
|
|
||||||
state = State.STOPPED;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,8 @@
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/frame_content">
|
android:id="@+id/frame_content">
|
||||||
|
|
||||||
<fragment
|
<FrameLayout
|
||||||
android:id="@+id/fragment_emulation"
|
android:id="@+id/frame_emulation_fragment"
|
||||||
android:name="org.dolphinemu.dolphinemu.fragments.EmulationFragment"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,8 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:id="@+id/frame_content">
|
android:id="@+id/frame_content">
|
||||||
|
|
||||||
<fragment
|
<FrameLayout
|
||||||
android:id="@+id/fragment_emulation"
|
android:id="@+id/frame_emulation_fragment"
|
||||||
android:name="org.dolphinemu.dolphinemu.fragments.EmulationFragment"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"/>
|
android:layout_height="match_parent"/>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue