diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java
index 7d55a89e2d..3cbbf3299a 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java
@@ -399,20 +399,6 @@ public final class NativeLibrary
}
}
- public static void endEmulationActivity()
- {
- Log.verbose("[NativeLibrary] Ending EmulationActivity.");
- EmulationActivity emulationActivity = sEmulationActivity.get();
- if (emulationActivity != null)
- {
- emulationActivity.exitWithAnimation();
- }
- else
- {
- Log.warning("[NativeLibrary] EmulationActivity is null, can't end.");
- }
- }
-
public static void setEmulationActivity(EmulationActivity emulationActivity)
{
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java
index 0748a34004..14d0e2c9be 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java
@@ -23,7 +23,6 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
@@ -55,8 +54,8 @@ public final class EmulationActivity extends AppCompatActivity
private static final String FRAGMENT_SUBMENU_TAG = "submenu";
private View mDecorView;
private ImageView mImageView;
+ private EmulationFragment mEmulationFragment;
- private FrameLayout mFrameEmulation;
private LinearLayout mMenuLayout;
private SharedPreferences mPreferences;
@@ -85,7 +84,6 @@ public final class EmulationActivity extends AppCompatActivity
}
};
private String mScreenPath;
- private FrameLayout mFrameContent;
private String mSelectedTitle;
@Retention(SOURCE)
@@ -219,12 +217,13 @@ public final class EmulationActivity extends AppCompatActivity
Java_GCAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
Java_WiimoteAdapter.manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+
setContentView(R.layout.activity_emulation);
mImageView = (ImageView) findViewById(R.id.image_screenshot);
- mFrameContent = (FrameLayout) findViewById(R.id.frame_content);
- mFrameEmulation = (FrameLayout) findViewById(R.id.frame_emulation_fragment);
mMenuLayout = (LinearLayout) findViewById(R.id.layout_ingame_menu);
+ mEmulationFragment = (EmulationFragment) getSupportFragmentManager()
+ .findFragmentById(R.id.fragment_emulation);
Intent gameToEmulate = getIntent();
String path = gameToEmulate.getStringExtra("SelectedGame");
@@ -260,14 +259,6 @@ public final class EmulationActivity extends AppCompatActivity
Animations.fadeViewOut(mImageView)
.setStartDelay(2000)
- .withStartAction(new Runnable()
- {
- @Override
- public void run()
- {
- mFrameEmulation.setVisibility(View.VISIBLE);
- }
- })
.withEndAction(new Runnable()
{
@Override
@@ -277,18 +268,12 @@ public final class EmulationActivity extends AppCompatActivity
}
});
- // Instantiate an EmulationFragment.
- EmulationFragment emulationFragment = EmulationFragment.newInstance(path);
-
- // Add fragment to the activity - this triggers all its lifecycle callbacks.
- getSupportFragmentManager().beginTransaction()
- .add(R.id.frame_emulation_fragment, emulationFragment, EmulationFragment.FRAGMENT_TAG)
- .commit();
+ mEmulationFragment.setGamePath(path);
+ mEmulationFragment.startEmulation();
}
else
{
mImageView.setVisibility(View.GONE);
- mFrameEmulation.setVisibility(View.VISIBLE);
}
if (mDeviceHasTouchScreen)
@@ -311,23 +296,6 @@ public final class EmulationActivity extends AppCompatActivity
mIsGameCubeGame = Platform.fromNativeInt(NativeLibrary.GetPlatform(path)) == Platform.GAMECUBE;
}
- @Override
- protected void onStart()
- {
- super.onStart();
- Log.debug("[EmulationActivity] EmulationActivity starting.");
- NativeLibrary.setEmulationActivity(this);
- }
-
- @Override
- protected void onStop()
- {
- super.onStop();
- Log.debug("[EmulationActivity] EmulationActivity stopping.");
-
- NativeLibrary.clearEmulationActivity();
- }
-
@Override
protected void onPostCreate(Bundle savedInstanceState)
{
@@ -376,7 +344,8 @@ public final class EmulationActivity extends AppCompatActivity
}
else
{
- stopEmulation();
+ mEmulationFragment.stopEmulation();
+ exitWithAnimation();
}
}
@@ -406,15 +375,6 @@ public final class EmulationActivity extends AppCompatActivity
}
}
- private void stopEmulation()
- {
- EmulationFragment fragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
- fragment.notifyEmulationStopped();
-
- NativeLibrary.StopEmulation();
- }
-
public void exitWithAnimation()
{
runOnUiThread(new Runnable()
@@ -458,7 +418,6 @@ public final class EmulationActivity extends AppCompatActivity
@Override
public void run()
{
- mFrameContent.removeView(mFrameEmulation);
setResult(mPosition);
finishAfterTransition();
}
@@ -599,20 +558,23 @@ public final class EmulationActivity extends AppCompatActivity
return;
case MENU_ACTION_EXIT:
- toggleMenu();
- stopEmulation();
+ toggleMenu(); // Hide the menu (it will be showing since we just clicked it)
+ mEmulationFragment.stopEmulation();
+ exitWithAnimation();
return;
}
}
- private void editControlsPlacement() {
- EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentById(R.id.frame_emulation_fragment);
- if (emulationFragment.isConfiguringControls()) {
- emulationFragment.stopConfiguringControls();
- } else {
- emulationFragment.startConfiguringControls();
+ private void editControlsPlacement()
+ {
+ if (mEmulationFragment.isConfiguringControls())
+ {
+ mEmulationFragment.stopConfiguringControls();
+ }
+ else
+ {
+ mEmulationFragment.startConfiguringControls();
}
}
@@ -701,20 +663,18 @@ public final class EmulationActivity extends AppCompatActivity
}
builder.setNeutralButton(getString(R.string.emulation_toggle_all), new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialogInterface, int i) {
- EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
- emulationFragment.toggleInputOverlayVisibility();
+ public void onClick(DialogInterface dialogInterface, int i)
+ {
+ mEmulationFragment.toggleInputOverlayVisibility();
}
});
builder.setPositiveButton(getString(R.string.ok), new DialogInterface.OnClickListener() {
@Override
- public void onClick(DialogInterface dialogInterface, int i) {
+ public void onClick(DialogInterface dialogInterface, int i)
+ {
editor.apply();
- EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
- emulationFragment.refreshInputOverlay();
+ mEmulationFragment.refreshInputOverlay();
}
});
@@ -759,9 +719,7 @@ public final class EmulationActivity extends AppCompatActivity
editor.putInt("controlScale", seekbar.getProgress());
editor.apply();
- EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
- emulationFragment.refreshInputOverlay();
+ mEmulationFragment.refreshInputOverlay();
}
});
@@ -788,9 +746,7 @@ public final class EmulationActivity extends AppCompatActivity
public void onClick(DialogInterface dialogInterface, int i) {
editor.apply();
- EmulationFragment emulationFragment = (EmulationFragment) getSupportFragmentManager()
- .findFragmentByTag(EmulationFragment.FRAGMENT_TAG);
- emulationFragment.refreshInputOverlay();
+ mEmulationFragment.refreshInputOverlay();
Toast.makeText(getApplication(), R.string.emulation_controller_changed, Toast.LENGTH_SHORT).show();
}
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 f80487b938..4ba035f950 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
@@ -1,5 +1,6 @@
package org.dolphinemu.dolphinemu.fragments;
+import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -14,15 +15,12 @@ import android.widget.Button;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.overlay.InputOverlay;
import org.dolphinemu.dolphinemu.utils.Log;
public final class EmulationFragment extends Fragment implements SurfaceHolder.Callback
{
- public static final String FRAGMENT_TAG = "emulation_fragment";
-
- private static final String ARG_GAME_PATH = "game_path";
-
private SharedPreferences mPreferences;
private Surface mSurface;
@@ -31,18 +29,22 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
private Thread mEmulationThread;
- private boolean mEmulationStarted;
- private boolean mEmulationRunning;
+ private String mGamePath;
+ private final EmulationState mEmulationState = new EmulationState();
- public static EmulationFragment newInstance(String path)
+ @Override
+ public void onAttach(Context context)
{
- EmulationFragment fragment = new EmulationFragment();
+ super.onAttach(context);
- Bundle arguments = new Bundle();
- arguments.putString(ARG_GAME_PATH, path);
- fragment.setArguments(arguments);
-
- return fragment;
+ if (context instanceof EmulationActivity)
+ {
+ NativeLibrary.setEmulationActivity((EmulationActivity) context);
+ }
+ else
+ {
+ throw new IllegalStateException("EmulationFragment must have EmulationActivity parent");
+ }
}
/**
@@ -67,38 +69,20 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
{
View contents = inflater.inflate(R.layout.fragment_emulation, container, false);
- SurfaceView surfaceView = (SurfaceView) contents.findViewById(R.id.surface_emulation);
- mInputOverlay = (InputOverlay) contents.findViewById(R.id.surface_input_overlay);
-
+ SurfaceView surfaceView = contents.findViewById(R.id.surface_emulation);
surfaceView.getHolder().addCallback(this);
- // If the input overlay was previously disabled, then don't show it.
+ mInputOverlay = contents.findViewById(R.id.surface_input_overlay);
if (mInputOverlay != null)
{
+ // If the input overlay was previously disabled, then don't show it.
if (!mPreferences.getBoolean("showInputOverlay", true))
{
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;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState)
- {
- Button doneButton = (Button) view.findViewById(R.id.done_control_config);
+ Button doneButton = contents.findViewById(R.id.done_control_config);
if (doneButton != null)
{
doneButton.setOnClickListener(new View.OnClickListener()
@@ -110,29 +94,29 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
}
});
}
- }
- @Override
- public void onStart()
- {
- super.onStart();
- startEmulation();
+ // The new Surface created here will get passed to the native code via onSurfaceChanged.
+
+ return contents;
}
@Override
public void onStop()
{
+ pauseEmulation();
super.onStop();
}
@Override
- public void onDestroyView()
+ public void onDetach()
{
- super.onDestroyView();
- if (getActivity().isFinishing() && mEmulationStarted)
- {
- NativeLibrary.StopEmulation();
- }
+ NativeLibrary.clearEmulationActivity();
+ super.onDetach();
+ }
+
+ public void setGamePath(String setPath)
+ {
+ this.mGamePath = setPath;
}
public void toggleInputOverlayVisibility()
@@ -171,6 +155,12 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
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);
}
@@ -181,45 +171,57 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
Log.debug("[EmulationFragment] Surface destroyed.");
NativeLibrary.SurfaceDestroyed();
- if (mEmulationRunning)
+ if (mEmulationState.isRunning())
{
pauseEmulation();
}
}
- private void startEmulation()
+ public void startEmulation()
{
- if (!mEmulationStarted)
+ synchronized (mEmulationState)
{
- Log.debug("[EmulationFragment] Starting emulation thread.");
+ if (mEmulationState.isStopped())
+ {
+ Log.debug("[EmulationFragment] Starting emulation thread.");
- mEmulationThread.start();
+ 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.");
+ }
}
- else
+ }
+
+ public void stopEmulation() {
+ synchronized (mEmulationState)
{
- Log.debug("[EmulationFragment] Resuming emulation.");
- NativeLibrary.UnPauseEmulation();
+ if (!mEmulationState.isStopped())
+ {
+ NativeLibrary.StopEmulation();
+ mEmulationState.stop();
+ }
}
-
- mEmulationRunning = true;
}
private void pauseEmulation()
{
- Log.debug("[EmulationFragment] Pausing emulation.");
+ synchronized (mEmulationState)
+ {
+ Log.debug("[EmulationFragment] Pausing emulation.");
- NativeLibrary.PauseEmulation();
- mEmulationRunning = false;
- }
-
- /**
- * Called by containing activity to tell the Fragment emulation is already stopping,
- * so it doesn't try to stop emulation on its way to the garbage collector.
- */
- public void notifyEmulationStopped()
- {
- mEmulationStarted = false;
- mEmulationRunning = false;
+ NativeLibrary.PauseEmulation();
+ mEmulationState.pause();
+ }
}
private Runnable mEmulationRunner = new Runnable()
@@ -227,18 +229,17 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
@Override
public void run()
{
- mEmulationRunning = true;
- mEmulationStarted = true;
+ // Busy-wait for surface to be set
+ while (mSurface == null) {}
- while (mSurface == null)
- if (!mEmulationRunning)
- return;
-
- Log.info("[EmulationFragment] Starting emulation: " + mSurface);
+ synchronized (mEmulationState)
+ {
+ Log.info("[EmulationFragment] Starting emulation: " + mSurface);
+ mEmulationState.run();
+ }
// Start emulation using the provided Surface.
- String path = getArguments().getString(ARG_GAME_PATH);
- NativeLibrary.Run(path);
+ NativeLibrary.Run(mGamePath);
}
};
@@ -258,4 +259,50 @@ public final class EmulationFragment extends Fragment implements SurfaceHolder.C
{
return mInputOverlay.isInEditMode();
}
+
+ private static class EmulationState
+ {
+ private enum State
+ {
+ STOPPED, RUNNING, PAUSED
+ }
+
+ private State state;
+
+ EmulationState()
+ {
+ // Starting state is stopped.
+ state = State.STOPPED;
+ }
+
+ public boolean isStopped()
+ {
+ return state == State.STOPPED;
+ }
+
+ public boolean isRunning()
+ {
+ return state == State.RUNNING;
+ }
+
+ public boolean isPaused()
+ {
+ return state == State.PAUSED;
+ }
+
+ public void run()
+ {
+ state = State.RUNNING;
+ }
+
+ public void pause()
+ {
+ state = State.PAUSED;
+ }
+
+ public void stop()
+ {
+ state = State.STOPPED;
+ }
+ }
}
diff --git a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml
index 59e1ba02ec..ad67bcb05e 100644
--- a/Source/Android/app/src/main/res/layout-television/activity_emulation.xml
+++ b/Source/Android/app/src/main/res/layout-television/activity_emulation.xml
@@ -5,11 +5,11 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/frame_content">
-
+ android:layout_height="match_parent"/>
-
+ android:layout_height="match_parent"/>
GetStaticMethodID(s_jni_class, "displayAlertMsg", "(Ljava/lang/String;)V");
- s_jni_method_end = env->GetStaticMethodID(s_jni_class, "endEmulationActivity", "()V");
}
// Surface Handling
@@ -816,9 +814,6 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_Run(JNIEnv*
ANativeWindow_release(s_surf);
s_surf = nullptr;
}
-
- // Execute the Java method.
- env->CallStaticVoidMethod(s_jni_class, s_jni_method_end);
}
#ifdef __cplusplus