mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 23:55:40 +00:00
Android: Fix emulation stopping on app switch and UI covering display
This commit is contained in:
parent
c360b41a79
commit
5aa1b9553f
|
@ -162,6 +162,11 @@ void AndroidHostInterface::UpdateInputMap()
|
||||||
CommonHostInterface::UpdateInputMap(m_settings_interface);
|
CommonHostInterface::UpdateInputMap(m_settings_interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AndroidHostInterface::IsEmulationThreadPaused() const
|
||||||
|
{
|
||||||
|
return System::IsValid() && System::IsPaused();
|
||||||
|
}
|
||||||
|
|
||||||
bool AndroidHostInterface::StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
bool AndroidHostInterface::StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
||||||
SystemBootParameters boot_params, bool resume_state)
|
SystemBootParameters boot_params, bool resume_state)
|
||||||
{
|
{
|
||||||
|
@ -176,11 +181,23 @@ bool AndroidHostInterface::StartEmulationThread(jobject emulation_activity, ANat
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AndroidHostInterface::PauseEmulationThread(bool paused)
|
||||||
|
{
|
||||||
|
Assert(IsEmulationThreadRunning());
|
||||||
|
RunOnEmulationThread([this, paused]() {
|
||||||
|
PauseSystem(paused);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::StopEmulationThread()
|
void AndroidHostInterface::StopEmulationThread()
|
||||||
{
|
{
|
||||||
Assert(IsEmulationThreadRunning());
|
Assert(IsEmulationThreadRunning());
|
||||||
Log_InfoPrint("Stopping emulation thread...");
|
Log_InfoPrint("Stopping emulation thread...");
|
||||||
m_emulation_thread_stop_request.store(true);
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
|
m_emulation_thread_stop_request.store(true);
|
||||||
|
m_sleep_cv.notify_one();
|
||||||
|
}
|
||||||
m_emulation_thread.join();
|
m_emulation_thread.join();
|
||||||
Log_InfoPrint("Emulation thread stopped");
|
Log_InfoPrint("Emulation thread stopped");
|
||||||
}
|
}
|
||||||
|
@ -193,8 +210,9 @@ void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_callback_mutex.lock();
|
m_mutex.lock();
|
||||||
m_callback_queue.push_back(std::move(function));
|
m_callback_queue.push_back(std::move(function));
|
||||||
|
m_sleep_cv.notify_one();
|
||||||
|
|
||||||
if (blocking)
|
if (blocking)
|
||||||
{
|
{
|
||||||
|
@ -204,12 +222,12 @@ void AndroidHostInterface::RunOnEmulationThread(std::function<void()> function,
|
||||||
if (m_callback_queue.empty())
|
if (m_callback_queue.empty())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
m_callback_mutex.unlock();
|
m_mutex.unlock();
|
||||||
m_callback_mutex.lock();
|
m_mutex.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_callback_mutex.unlock();
|
m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
||||||
|
@ -254,22 +272,44 @@ void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity,
|
||||||
|
|
||||||
// System is ready to go.
|
// System is ready to go.
|
||||||
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
|
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStarted);
|
||||||
while (!m_emulation_thread_stop_request.load())
|
EmulationThreadLoop();
|
||||||
|
|
||||||
|
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
||||||
|
PowerOffSystem();
|
||||||
|
DestroyImGuiContext();
|
||||||
|
thread_env->DeleteGlobalRef(m_emulation_activity_object);
|
||||||
|
m_emulation_activity_object = {};
|
||||||
|
s_jvm->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AndroidHostInterface::EmulationThreadLoop()
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
{
|
{
|
||||||
// run any events
|
// run any events
|
||||||
m_callback_mutex.lock();
|
|
||||||
for (;;)
|
|
||||||
{
|
{
|
||||||
if (m_callback_queue.empty())
|
std::unique_lock<std::mutex> lock(m_mutex);
|
||||||
break;
|
for (;;) {
|
||||||
|
while (!m_callback_queue.empty()) {
|
||||||
|
auto callback = std::move(m_callback_queue.front());
|
||||||
|
m_callback_queue.pop_front();
|
||||||
|
lock.unlock();
|
||||||
|
callback();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
auto callback = std::move(m_callback_queue.front());
|
if (m_emulation_thread_stop_request.load())
|
||||||
m_callback_queue.pop_front();
|
return;
|
||||||
m_callback_mutex.unlock();
|
|
||||||
callback();
|
if (System::IsPaused()) {
|
||||||
m_callback_mutex.lock();
|
// paused, wait for us to resume
|
||||||
|
m_sleep_cv.wait(lock);
|
||||||
|
} else {
|
||||||
|
// done with callbacks, run the frame
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
m_callback_mutex.unlock();
|
|
||||||
|
|
||||||
// simulate the system if not paused
|
// simulate the system if not paused
|
||||||
if (System::IsRunning())
|
if (System::IsRunning())
|
||||||
|
@ -291,13 +331,6 @@ void AndroidHostInterface::EmulationThreadEntryPoint(jobject emulation_activity,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
thread_env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onEmulationStopped);
|
|
||||||
PowerOffSystem();
|
|
||||||
DestroyImGuiContext();
|
|
||||||
thread_env->DeleteGlobalRef(m_emulation_activity_object);
|
|
||||||
m_emulation_activity_object = {};
|
|
||||||
s_jvm->DetachCurrentThread();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AndroidHostInterface::AcquireHostDisplay()
|
bool AndroidHostInterface::AcquireHostDisplay()
|
||||||
|
@ -373,7 +406,7 @@ void AndroidHostInterface::SurfaceChanged(ANativeWindow* surface, int format, in
|
||||||
if (m_display)
|
if (m_display)
|
||||||
{
|
{
|
||||||
WindowInfo wi;
|
WindowInfo wi;
|
||||||
wi.type = WindowInfo::Type::Android;
|
wi.type = surface ? WindowInfo::Type::Android : WindowInfo::Type::Surfaceless;
|
||||||
wi.window_handle = surface;
|
wi.window_handle = surface;
|
||||||
wi.surface_width = width;
|
wi.surface_width = width;
|
||||||
wi.surface_height = height;
|
wi.surface_height = height;
|
||||||
|
@ -588,8 +621,8 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_stopEmulationThread, jobject o
|
||||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width,
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_surfaceChanged, jobject obj, jobject surface, jint format, jint width,
|
||||||
jint height)
|
jint height)
|
||||||
{
|
{
|
||||||
ANativeWindow* native_surface = ANativeWindow_fromSurface(env, surface);
|
ANativeWindow* native_surface = surface ? ANativeWindow_fromSurface(env, surface) : nullptr;
|
||||||
if (!native_surface)
|
if (surface && !native_surface)
|
||||||
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
Log_ErrorPrint("ANativeWindow_fromSurface() returned null");
|
||||||
|
|
||||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
|
@ -724,9 +757,39 @@ DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveState, jobject obj, jboole
|
||||||
hi->RunOnEmulationThread([hi, global, slot]() { hi->SaveState(global, slot); });
|
hi->RunOnEmulationThread([hi, global, slot]() { hi->SaveState(global, slot); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_saveResumeState, jobject obj, jboolean wait_for_completion)
|
||||||
|
{
|
||||||
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
|
hi->RunOnEmulationThread([hi]() { hi->SaveResumeSaveState(); }, wait_for_completion);
|
||||||
|
}
|
||||||
|
|
||||||
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setDisplayAlignment, jobject obj, jint alignment)
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_setDisplayAlignment, jobject obj, jint alignment)
|
||||||
{
|
{
|
||||||
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
hi->RunOnEmulationThread([hi, alignment]() { hi->GetDisplay()->SetDisplayAlignment(static_cast<HostDisplay::Alignment>(alignment)); });
|
hi->RunOnEmulationThread([hi, alignment]() { hi->GetDisplay()->SetDisplayAlignment(static_cast<HostDisplay::Alignment>(alignment)); });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_hasSurface, jobject obj)
|
||||||
|
{
|
||||||
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
|
HostDisplay* display = hi->GetDisplay();
|
||||||
|
if (display)
|
||||||
|
return display->HasRenderSurface();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_JNI_ARGS_METHOD(bool, AndroidHostInterface_isEmulationThreadPaused, jobject obj)
|
||||||
|
{
|
||||||
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
|
return hi->IsEmulationThreadPaused();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFINE_JNI_ARGS_METHOD(void, AndroidHostInterface_pauseEmulationThread, jobject obj, jboolean paused)
|
||||||
|
{
|
||||||
|
AndroidHostInterface* hi = AndroidHelpers::GetNativeClass(env, obj);
|
||||||
|
hi->PauseEmulationThread(paused);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "frontend-common/common_host_interface.h"
|
#include "frontend-common/common_host_interface.h"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -35,9 +36,11 @@ public:
|
||||||
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f) override;
|
||||||
|
|
||||||
bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
|
bool IsEmulationThreadRunning() const { return m_emulation_thread.joinable(); }
|
||||||
|
bool IsEmulationThreadPaused() const;
|
||||||
bool StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
bool StartEmulationThread(jobject emulation_activity, ANativeWindow* initial_surface,
|
||||||
SystemBootParameters boot_params, bool resume_state);
|
SystemBootParameters boot_params, bool resume_state);
|
||||||
void RunOnEmulationThread(std::function<void()> function, bool blocking = false);
|
void RunOnEmulationThread(std::function<void()> function, bool blocking = false);
|
||||||
|
void PauseEmulationThread(bool paused);
|
||||||
void StopEmulationThread();
|
void StopEmulationThread();
|
||||||
|
|
||||||
void SurfaceChanged(ANativeWindow* surface, int format, int width, int height);
|
void SurfaceChanged(ANativeWindow* surface, int format, int width, int height);
|
||||||
|
@ -63,6 +66,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
void EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
void EmulationThreadEntryPoint(jobject emulation_activity, ANativeWindow* initial_surface,
|
||||||
SystemBootParameters boot_params, bool resume_state);
|
SystemBootParameters boot_params, bool resume_state);
|
||||||
|
void EmulationThreadLoop();
|
||||||
|
|
||||||
void CreateImGuiContext();
|
void CreateImGuiContext();
|
||||||
void DestroyImGuiContext();
|
void DestroyImGuiContext();
|
||||||
|
@ -74,7 +78,8 @@ private:
|
||||||
|
|
||||||
ANativeWindow* m_surface = nullptr;
|
ANativeWindow* m_surface = nullptr;
|
||||||
|
|
||||||
std::mutex m_callback_mutex;
|
std::mutex m_mutex;
|
||||||
|
std::condition_variable m_sleep_cv;
|
||||||
std::deque<std::function<void()>> m_callback_queue;
|
std::deque<std::function<void()>> m_callback_queue;
|
||||||
|
|
||||||
std::thread m_emulation_thread;
|
std::thread m_emulation_thread;
|
||||||
|
|
|
@ -34,8 +34,14 @@ public class AndroidHostInterface {
|
||||||
|
|
||||||
public native boolean startEmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String state_filename);
|
public native boolean startEmulationThread(EmulationActivity emulationActivity, Surface surface, String filename, boolean resumeState, String state_filename);
|
||||||
|
|
||||||
|
public native boolean isEmulationThreadPaused();
|
||||||
|
|
||||||
|
public native void pauseEmulationThread(boolean paused);
|
||||||
|
|
||||||
public native void stopEmulationThread();
|
public native void stopEmulationThread();
|
||||||
|
|
||||||
|
public native boolean hasSurface();
|
||||||
|
|
||||||
public native void surfaceChanged(Surface surface, int format, int width, int height);
|
public native void surfaceChanged(Surface surface, int format, int width, int height);
|
||||||
|
|
||||||
// TODO: Find a better place for this.
|
// TODO: Find a better place for this.
|
||||||
|
@ -59,6 +65,8 @@ public class AndroidHostInterface {
|
||||||
|
|
||||||
public native void saveState(boolean global, int slot);
|
public native void saveState(boolean global, int slot);
|
||||||
|
|
||||||
|
public native void saveResumeState(boolean waitForCompletion);
|
||||||
|
|
||||||
public native void applySettings();
|
public native void applySettings();
|
||||||
|
|
||||||
public native void setDisplayAlignment(int alignment);
|
public native void setDisplayAlignment(int alignment);
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.github.stenzek.duckstation;
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
@ -12,6 +13,7 @@ import android.content.SharedPreferences;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
|
import android.util.AndroidException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
|
@ -30,7 +32,10 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
/**
|
/**
|
||||||
* Settings interfaces.
|
* Settings interfaces.
|
||||||
*/
|
*/
|
||||||
SharedPreferences mPreferences;
|
private SharedPreferences mPreferences;
|
||||||
|
private boolean mWasDestroyed = false;
|
||||||
|
private boolean mWasPausedOnSurfaceLoss = false;
|
||||||
|
private boolean mApplySettingsOnSurfaceRestored = false;
|
||||||
|
|
||||||
private boolean getBooleanSetting(String key, boolean defaultValue) {
|
private boolean getBooleanSetting(String key, boolean defaultValue) {
|
||||||
return mPreferences.getBoolean(key, defaultValue);
|
return mPreferences.getBoolean(key, defaultValue);
|
||||||
|
@ -85,7 +90,8 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
|
|
||||||
public void onEmulationStopped() {
|
public void onEmulationStopped() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
finish();
|
if (!mWasDestroyed)
|
||||||
|
finish();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +101,16 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applySettings() {
|
||||||
|
if (!AndroidHostInterface.getInstance().isEmulationThreadRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (AndroidHostInterface.getInstance().hasSurface())
|
||||||
|
AndroidHostInterface.getInstance().applySettings();
|
||||||
|
else
|
||||||
|
mApplySettingsOnSurfaceRestored = true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void surfaceCreated(SurfaceHolder holder) {
|
public void surfaceCreated(SurfaceHolder holder) {
|
||||||
}
|
}
|
||||||
|
@ -103,8 +119,19 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
|
||||||
// Once we get a surface, we can boot.
|
// Once we get a surface, we can boot.
|
||||||
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
||||||
|
final boolean hadSurface = AndroidHostInterface.getInstance().hasSurface();
|
||||||
AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height);
|
AndroidHostInterface.getInstance().surfaceChanged(holder.getSurface(), format, width, height);
|
||||||
updateOrientation();
|
updateOrientation();
|
||||||
|
|
||||||
|
if (holder.getSurface() != null && !hadSurface && AndroidHostInterface.getInstance().isEmulationThreadPaused() && !mWasPausedOnSurfaceLoss) {
|
||||||
|
AndroidHostInterface.getInstance().pauseEmulationThread(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mApplySettingsOnSurfaceRestored) {
|
||||||
|
AndroidHostInterface.getInstance().applySettings();
|
||||||
|
mApplySettingsOnSurfaceRestored = false;
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,14 +148,21 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
if (!AndroidHostInterface.getInstance().isEmulationThreadRunning())
|
if (!AndroidHostInterface.getInstance().isEmulationThreadRunning())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Log.i("EmulationActivity", "Stopping emulation thread");
|
Log.i("EmulationActivity", "Surface destroyed");
|
||||||
AndroidHostInterface.getInstance().stopEmulationThread();
|
|
||||||
|
// Save the resume state in case we never get back again...
|
||||||
|
AndroidHostInterface.getInstance().saveResumeState(true);
|
||||||
|
|
||||||
|
mWasPausedOnSurfaceLoss = AndroidHostInterface.getInstance().isEmulationThreadPaused();
|
||||||
|
AndroidHostInterface.getInstance().pauseEmulationThread(true);
|
||||||
|
AndroidHostInterface.getInstance().surfaceChanged(null, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
mPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
Log.i("EmulationActivity", "OnCreate");
|
||||||
|
|
||||||
setContentView(R.layout.activity_emulation);
|
setContentView(R.layout.activity_emulation);
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
|
@ -167,10 +201,20 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onStop() {
|
protected void onPostResume() {
|
||||||
super.onStop();
|
super.onPostResume();
|
||||||
|
if (!mSystemUIVisible)
|
||||||
|
hideSystemUI();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
Log.i("EmulationActivity", "OnStop");
|
||||||
|
showSystemUI(false);
|
||||||
|
|
||||||
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
if (AndroidHostInterface.getInstance().isEmulationThreadRunning()) {
|
||||||
|
mWasDestroyed = true;
|
||||||
AndroidHostInterface.getInstance().stopEmulationThread();
|
AndroidHostInterface.getInstance().stopEmulationThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,6 +229,8 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final int REQUEST_CODE_SETTINGS = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
// Handle action bar item clicks here. The action bar will
|
// Handle action bar item clicks here. The action bar will
|
||||||
|
@ -195,7 +241,8 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
//noinspection SimplifiableIfStatement
|
//noinspection SimplifiableIfStatement
|
||||||
if (id == R.id.action_settings) {
|
if (id == R.id.action_settings) {
|
||||||
Intent intent = new Intent(this, SettingsActivity.class);
|
Intent intent = new Intent(this, SettingsActivity.class);
|
||||||
startActivity(intent);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
|
startActivityForResult(intent, REQUEST_CODE_SETTINGS);
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.show_controller) {
|
} else if (id == R.id.show_controller) {
|
||||||
setTouchscreenControllerVisibility(!mTouchscreenControllerVisible);
|
setTouchscreenControllerVisibility(!mTouchscreenControllerVisible);
|
||||||
|
@ -205,7 +252,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
boolean newSetting = !getBooleanSetting("Main/SpeedLimiterEnabled", true);
|
boolean newSetting = !getBooleanSetting("Main/SpeedLimiterEnabled", true);
|
||||||
setBooleanSetting("Main/SpeedLimiterEnabled", newSetting);
|
setBooleanSetting("Main/SpeedLimiterEnabled", newSetting);
|
||||||
item.setChecked(newSetting);
|
item.setChecked(newSetting);
|
||||||
AndroidHostInterface.getInstance().applySettings();
|
applySettings();
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.reset) {
|
} else if (id == R.id.reset) {
|
||||||
AndroidHostInterface.getInstance().resetSystem();
|
AndroidHostInterface.getInstance().resetSystem();
|
||||||
|
@ -221,6 +268,17 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (requestCode == REQUEST_CODE_SETTINGS) {
|
||||||
|
// TODO: Sync any menu settings.
|
||||||
|
if (AndroidHostInterface.getInstance().isEmulationThreadRunning())
|
||||||
|
applySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
if (mSystemUIVisible) {
|
if (mSystemUIVisible) {
|
||||||
|
@ -228,7 +286,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showSystemUI();
|
showSystemUI(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -308,24 +366,17 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressLint("InlinedApi")
|
@SuppressLint("InlinedApi")
|
||||||
private void showSystemUI() {
|
private void showSystemUI(boolean delay) {
|
||||||
// Show the system bar
|
// Show the system bar
|
||||||
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
mContentView.setSystemUiVisibility(0);
|
||||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
|
|
||||||
mSystemUIVisible = true;
|
mSystemUIVisible = true;
|
||||||
|
|
||||||
// Schedule a runnable to display UI elements after a delay
|
// Schedule a runnable to display UI elements after a delay
|
||||||
mSystemUIHideHandler.removeCallbacks(mHidePart2Runnable);
|
mSystemUIHideHandler.removeCallbacks(mHidePart2Runnable);
|
||||||
mSystemUIHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
|
if (delay)
|
||||||
}
|
mSystemUIHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
|
||||||
|
else
|
||||||
/**
|
mShowPart2Runnable.run();
|
||||||
* Schedules a call to hide() in delay milliseconds, canceling any
|
|
||||||
* previously scheduled calls.
|
|
||||||
*/
|
|
||||||
private void delayedHide(int delayMillis) {
|
|
||||||
mSystemUIHideHandler.removeCallbacks(mHideRunnable);
|
|
||||||
mSystemUIHideHandler.postDelayed(mHideRunnable, delayMillis);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue