Skip to content

Commit

Permalink
Android: Use DialogFragment for AlertMessage
Browse files Browse the repository at this point in the history
  • Loading branch information
Ebola16 committed Aug 2, 2020
1 parent 7414020 commit 2187b03
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
package org.dolphinemu.dolphinemu;

import android.view.Surface;

import androidx.appcompat.app.AlertDialog;
import android.widget.Toast;

import org.dolphinemu.dolphinemu.activities.EmulationActivity;
import org.dolphinemu.dolphinemu.dialogs.AlertMessage;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.Rumble;

Expand All @@ -23,6 +23,9 @@
*/
public final class NativeLibrary
{
private static final Object sAlertMessageLock = new Object();
private static boolean sIsShowingAlertMessage = false;

private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);

/**
Expand Down Expand Up @@ -424,6 +427,8 @@ public static native String GetConfig(String configFile, String Section, String
*/
public static native void StopEmulation();

public static native boolean IsBooting();

public static native void WaitUntilDoneBooting();

/**
Expand Down Expand Up @@ -463,8 +468,6 @@ public static native String GetConfig(String configFile, String Section, String

public static native String FormatSize(long bytes, int decimals);

private static boolean alertResult = false;

public static boolean displayAlertMsg(final String caption, final String text,
final boolean yesNo)
{
Expand All @@ -477,74 +480,57 @@ public static boolean displayAlertMsg(final String caption, final String text,
}
else
{
// Create object used for waiting.
final Object lock = new Object();
AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity,
R.style.DolphinDialogBase)
.setTitle(caption)
.setMessage(text);

// If not yes/no dialog just have one button that dismisses modal,
// otherwise have a yes and no button that sets alertResult accordingly.
if (!yesNo)
// AlertMessages while the core is booting will deadlock when WaitUntilDoneBooting is called.
// Report the AlertMessage text as a toast instead.
if (IsBooting())
{
builder
.setCancelable(false)
.setPositiveButton("OK", (dialog, whichButton) ->
{
dialog.dismiss();
synchronized (lock)
{
lock.notify();
}
});
emulationActivity.runOnUiThread(
() -> Toast.makeText(emulationActivity.getApplicationContext(), text,
Toast.LENGTH_LONG)
.show());
}
else
{
alertResult = false;

builder
.setPositiveButton("Yes", (dialog, whichButton) ->
{
alertResult = true;
dialog.dismiss();
synchronized (lock)
{
lock.notify();
}
})
.setNegativeButton("No", (dialog, whichButton) ->
{
alertResult = false;
dialog.dismiss();
synchronized (lock)
{
lock.notify();
}
});
}
sIsShowingAlertMessage = true;

// Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(builder::show);
emulationActivity.runOnUiThread(() -> AlertMessage.newInstance(caption, text, yesNo)
.show(emulationActivity.getSupportFragmentManager(), "AlertMessage"));

// Wait for the lock to notify that it is complete.
synchronized (lock)
{
try
// Wait for the lock to notify that it is complete.
synchronized (sAlertMessageLock)
{
lock.wait();
try
{
sAlertMessageLock.wait();
}
catch (Exception ignored)
{
}
}
catch (Exception ignored)

if (yesNo)
{
result = AlertMessage.GetAlertResult();
}
}

if (yesNo)
result = alertResult;
}
sIsShowingAlertMessage = false;
return result;
}

public static boolean IsShowingAlertMessage()
{
return sIsShowingAlertMessage;
}

public static void NotifyAlertMessageLock()
{
synchronized (sAlertMessageLock)
{
sAlertMessageLock.notify();
}
}

public static void setEmulationActivity(EmulationActivity emulationActivity)
{
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,8 @@ protected void onCreate(Bundle savedInstanceState)
mPlatform = gameToEmulate.getIntExtra(EXTRA_PLATFORM, 0);
sUserPausedEmulation = gameToEmulate.getBooleanExtra(EXTRA_USER_PAUSED_EMULATION, false);
activityRecreated = false;
Toast.makeText(this, getString(R.string.emulation_touch_button_help), Toast.LENGTH_LONG)
.show();
}
else
{
Expand Down Expand Up @@ -337,8 +339,6 @@ protected void onCreate(Bundle savedInstanceState)
});
// Set these options now so that the SurfaceView the game renders into is the right size.
enableFullscreenImmersive();
Toast.makeText(this, getString(R.string.emulation_touch_button_help), Toast.LENGTH_LONG)
.show();
}
else
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.dolphinemu.dolphinemu.dialogs;

import android.app.Dialog;
import android.os.Bundle;

import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.activities.EmulationActivity;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;

public final class AlertMessage extends DialogFragment
{
private static boolean sAlertResult = false;
private static final String ARG_TITLE = "title";
private static final String ARG_MESSAGE = "message";
private static final String ARG_YES_NO = "yesNo";

public static AlertMessage newInstance(String title, String message, boolean yesNo)
{
AlertMessage fragment = new AlertMessage();

Bundle args = new Bundle();
args.putString(ARG_TITLE, title);
args.putString(ARG_MESSAGE, message);
args.putBoolean(ARG_YES_NO, yesNo);
fragment.setArguments(args);

return fragment;
}

@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
final EmulationActivity emulationActivity = NativeLibrary.getEmulationActivity();
String title = requireArguments().getString(ARG_TITLE);
String message = requireArguments().getString(ARG_MESSAGE);
boolean yesNo = requireArguments().getBoolean(ARG_YES_NO);
setCancelable(false);

AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity,
R.style.DolphinDialogBase)
.setTitle(title)
.setMessage(message);

// If not yes/no dialog just have one button that dismisses modal,
// otherwise have a yes and no button that sets sAlertResult accordingly.
if (!yesNo)
{
builder.setPositiveButton(android.R.string.ok, (dialog, which) ->
{
dialog.dismiss();
NativeLibrary.NotifyAlertMessageLock();
});
}
else
{
builder.setPositiveButton(android.R.string.yes, (dialog, which) ->
{
sAlertResult = true;
dialog.dismiss();
NativeLibrary.NotifyAlertMessageLock();
})
.setNegativeButton(android.R.string.no, (dialog, which) ->
{
sAlertResult = false;
dialog.dismiss();
NativeLibrary.NotifyAlertMessageLock();
});
}
return builder.create();
}

public static boolean GetAlertResult()
{
return sAlertResult;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,11 @@ public void onPause()
directoryStateReceiver = null;
}

if (mEmulationState.isRunning())
if (mEmulationState.isRunning() && !NativeLibrary.IsShowingAlertMessage())
{
mEmulationState.pause();
}

super.onPause();
}

Expand Down Expand Up @@ -379,7 +382,7 @@ public synchronized void clearSurface()
mSurface = null;
Log.debug("[EmulationFragment] Surface destroyed.");

if (state != State.STOPPED)
if (state != State.STOPPED && !NativeLibrary.IsShowingAlertMessage())
{
// In order to avoid dereferencing nullptr, we must not destroy the surface while booting
// the core, so wait here if necessary. An easy (but not 100% consistent) way to reach
Expand Down Expand Up @@ -418,7 +421,8 @@ private void runWithValidSurface()
else if (state == State.PAUSED)
{
NativeLibrary.SurfaceChanged(mSurface);
if (!EmulationActivity.getHasUserPausedEmulation())
if (!EmulationActivity.getHasUserPausedEmulation() &&
!NativeLibrary.IsShowingAlertMessage())
{
Log.debug("[EmulationFragment] Resuming emulation.");
NativeLibrary.UnPauseEmulation();
Expand Down
8 changes: 8 additions & 0 deletions Source/Android/jni/MainAndroid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_PauseEmulati
jobject obj);
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulation(JNIEnv* env,
jobject obj);
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsBooting(JNIEnv* env,
jobject obj);
JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj);
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsRunning(JNIEnv* env,
Expand Down Expand Up @@ -287,6 +289,12 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_StopEmulatio
s_update_main_frame_event.Set(); // Kick the waiting event
}

JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_IsBooting(JNIEnv* env,
jobject obj)
{
return static_cast<jboolean>(Core::IsBooting());
}

JNIEXPORT void JNICALL
Java_org_dolphinemu_dolphinemu_NativeLibrary_WaitUntilDoneBooting(JNIEnv* env, jobject obj)
{
Expand Down
7 changes: 6 additions & 1 deletion Source/Core/Core/Core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ void DisplayMessage(std::string message, int time_in_ms)
OSD::AddMessage(std::move(message), time_in_ms);
}

bool IsBooting()
{
return s_is_booting.IsSet() || !s_hardware_initialized;
}

bool IsRunning()
{
return (GetState() != State::Uninitialized || s_hardware_initialized) && !s_is_stopping;
Expand Down Expand Up @@ -674,7 +679,7 @@ State GetState()

void WaitUntilDoneBooting()
{
if (s_is_booting.IsSet() || !s_hardware_initialized)
if (IsBooting())
s_done_booting.Wait();
}

Expand Down
1 change: 1 addition & 0 deletions Source/Core/Core/Core.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ void UndeclareAsCPUThread();

std::string StopMessage(bool main_thread, std::string_view message);

bool IsBooting();
bool IsRunning();
bool IsRunningAndStarted(); // is running and the CPU loop has been entered
bool IsRunningInCurrentThread(); // this tells us whether we are running in the CPU thread.
Expand Down

0 comments on commit 2187b03

Please sign in to comment.