Android: Add a progress dialog for disc image conversion
This commit is contained in:
parent
7d6debb907
commit
d9f3e382fe
|
@ -12,6 +12,7 @@ import android.view.Surface;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
|
||||||
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
import org.dolphinemu.dolphinemu.activities.EmulationActivity;
|
||||||
|
import org.dolphinemu.dolphinemu.utils.CompressCallback;
|
||||||
import org.dolphinemu.dolphinemu.utils.Log;
|
import org.dolphinemu.dolphinemu.utils.Log;
|
||||||
import org.dolphinemu.dolphinemu.utils.Rumble;
|
import org.dolphinemu.dolphinemu.utils.Rumble;
|
||||||
|
|
||||||
|
@ -430,7 +431,8 @@ public final class NativeLibrary
|
||||||
public static native boolean InstallWAD(String file);
|
public static native boolean InstallWAD(String file);
|
||||||
|
|
||||||
public static native boolean ConvertDiscImage(String inPath, String outPath, int platform,
|
public static native boolean ConvertDiscImage(String inPath, String outPath, int platform,
|
||||||
int format, int blockSize, int compression, int compressionLevel, boolean scrub);
|
int format, int blockSize, int compression, int compressionLevel, boolean scrub,
|
||||||
|
CompressCallback callback);
|
||||||
|
|
||||||
public static native String FormatSize(long bytes, int decimals);
|
public static native String FormatSize(long bytes, int decimals);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package org.dolphinemu.dolphinemu.fragments;
|
package org.dolphinemu.dolphinemu.fragments;
|
||||||
|
|
||||||
|
import android.app.ProgressDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
|
@ -108,6 +109,9 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
|
||||||
|
|
||||||
private GameFile gameFile;
|
private GameFile gameFile;
|
||||||
|
|
||||||
|
private volatile boolean mCanceled;
|
||||||
|
private volatile Thread mThread = null;
|
||||||
|
|
||||||
public static ConvertFragment newInstance(String gamePath)
|
public static ConvertFragment newInstance(String gamePath)
|
||||||
{
|
{
|
||||||
Bundle args = new Bundle();
|
Bundle args = new Bundle();
|
||||||
|
@ -181,6 +185,15 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
|
||||||
valueWrapper.setPosition(i);
|
valueWrapper.setPosition(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onStop()
|
||||||
|
{
|
||||||
|
super.onStop();
|
||||||
|
|
||||||
|
mCanceled = true;
|
||||||
|
joinThread();
|
||||||
|
}
|
||||||
|
|
||||||
private Spinner populateSpinner(int spinnerId, int entriesId, int valuesId,
|
private Spinner populateSpinner(int spinnerId, int entriesId, int valuesId,
|
||||||
SpinnerValue valueWrapper)
|
SpinnerValue valueWrapper)
|
||||||
{
|
{
|
||||||
|
@ -339,33 +352,88 @@ public class ConvertFragment extends Fragment implements View.OnClickListener
|
||||||
|
|
||||||
private void convert()
|
private void convert()
|
||||||
{
|
{
|
||||||
|
final int PROGRESS_RESOLUTION = 1000;
|
||||||
|
|
||||||
Context context = requireContext();
|
Context context = requireContext();
|
||||||
|
|
||||||
// TODO: Let the user select a path
|
// TODO: Let the user select a path
|
||||||
String outPath = gameFile.getPath() + ".converted";
|
String outPath = gameFile.getPath() + ".converted";
|
||||||
|
|
||||||
boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath,
|
joinThread();
|
||||||
gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context,0),
|
|
||||||
mCompression.getValueOr(context,0), mCompressionLevel.getValueOr(context,0),
|
|
||||||
getRemoveJunkData());
|
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.DolphinDialogBase);
|
mCanceled = false;
|
||||||
if (success)
|
|
||||||
|
ProgressDialog progressDialog = new ProgressDialog(context, R.style.DolphinDialogBase);
|
||||||
|
|
||||||
|
progressDialog.setTitle(R.string.convert_converting);
|
||||||
|
|
||||||
|
progressDialog.setIndeterminate(false);
|
||||||
|
progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
|
||||||
|
progressDialog.setMax(PROGRESS_RESOLUTION);
|
||||||
|
|
||||||
|
progressDialog.setCancelable(true);
|
||||||
|
progressDialog.setOnCancelListener((dialog) -> mCanceled = true);
|
||||||
|
|
||||||
|
progressDialog.show();
|
||||||
|
|
||||||
|
mThread = new Thread(() ->
|
||||||
{
|
{
|
||||||
builder.setMessage(R.string.convert_success_message)
|
boolean success = NativeLibrary.ConvertDiscImage(gameFile.getPath(), outPath,
|
||||||
.setCancelable(false)
|
gameFile.getPlatform(), mFormat.getValue(context), mBlockSize.getValueOr(context, 0),
|
||||||
.setPositiveButton(R.string.ok, (dialog, i) ->
|
mCompression.getValueOr(context, 0), mCompressionLevel.getValueOr(context, 0),
|
||||||
|
getRemoveJunkData(), (text, completion) ->
|
||||||
{
|
{
|
||||||
dialog.dismiss();
|
requireActivity().runOnUiThread(() ->
|
||||||
requireActivity().finish();
|
{
|
||||||
|
progressDialog.setMessage(text);
|
||||||
|
progressDialog.setProgress((int) (completion * PROGRESS_RESOLUTION));
|
||||||
|
});
|
||||||
|
|
||||||
|
return !mCanceled;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
else
|
if (!mCanceled)
|
||||||
|
{
|
||||||
|
requireActivity().runOnUiThread(() ->
|
||||||
|
{
|
||||||
|
progressDialog.dismiss();
|
||||||
|
|
||||||
|
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.DolphinDialogBase);
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
builder.setMessage(R.string.convert_success_message)
|
||||||
|
.setCancelable(false)
|
||||||
|
.setPositiveButton(R.string.ok, (dialog, i) ->
|
||||||
|
{
|
||||||
|
dialog.dismiss();
|
||||||
|
requireActivity().finish();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
builder.setMessage(R.string.convert_failure_message)
|
||||||
|
.setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss());
|
||||||
|
}
|
||||||
|
AlertDialog alert = builder.create();
|
||||||
|
alert.show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
mThread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void joinThread()
|
||||||
|
{
|
||||||
|
if (mThread != null)
|
||||||
{
|
{
|
||||||
builder.setMessage(R.string.convert_failure_message)
|
try
|
||||||
.setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss());
|
{
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
catch (InterruptedException ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
AlertDialog alert = builder.create();
|
|
||||||
alert.show();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package org.dolphinemu.dolphinemu.utils;
|
||||||
|
|
||||||
|
public interface CompressCallback
|
||||||
|
{
|
||||||
|
boolean run(String text, float completion);
|
||||||
|
}
|
|
@ -337,6 +337,7 @@
|
||||||
<string name="convert_compression_level">Compression Level</string>
|
<string name="convert_compression_level">Compression Level</string>
|
||||||
<string name="convert_remove_junk_data">Remove Junk Data (Irreversible)</string>
|
<string name="convert_remove_junk_data">Remove Junk Data (Irreversible)</string>
|
||||||
<string name="convert_convert">Convert</string>
|
<string name="convert_convert">Convert</string>
|
||||||
|
<string name="convert_converting">Converting</string>
|
||||||
<string name="convert_warning_iso">Removing junk data does not save any space when converting to ISO (unless you package the ISO file in a compressed file format such as ZIP afterwards). Do you want to continue anyway?</string>
|
<string name="convert_warning_iso">Removing junk data does not save any space when converting to ISO (unless you package the ISO file in a compressed file format such as ZIP afterwards). Do you want to continue anyway?</string>
|
||||||
<string name="convert_warning_gcz">Converting Wii disc images to GCZ without removing junk data does not save any noticeable amount of space compared to converting to ISO. Do you want to continue anyway?</string>
|
<string name="convert_warning_gcz">Converting Wii disc images to GCZ without removing junk data does not save any noticeable amount of space compared to converting to ISO. Do you want to continue anyway?</string>
|
||||||
<string name="convert_success_message">The disc image was successfully converted.</string>
|
<string name="convert_success_message">The disc image was successfully converted.</string>
|
||||||
|
|
|
@ -36,6 +36,9 @@ static jclass s_ini_file_section_class;
|
||||||
static jfieldID s_ini_file_section_pointer;
|
static jfieldID s_ini_file_section_pointer;
|
||||||
static jmethodID s_ini_file_section_constructor;
|
static jmethodID s_ini_file_section_constructor;
|
||||||
|
|
||||||
|
static jclass s_compress_cb_class;
|
||||||
|
static jmethodID s_compress_cb_run;
|
||||||
|
|
||||||
namespace IDCache
|
namespace IDCache
|
||||||
{
|
{
|
||||||
JNIEnv* GetEnvForThread()
|
JNIEnv* GetEnvForThread()
|
||||||
|
@ -161,6 +164,16 @@ jmethodID GetIniFileSectionConstructor()
|
||||||
return s_ini_file_section_constructor;
|
return s_ini_file_section_constructor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jclass GetCompressCallbackClass()
|
||||||
|
{
|
||||||
|
return s_compress_cb_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID GetCompressCallbackRun()
|
||||||
|
{
|
||||||
|
return s_compress_cb_run;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -223,6 +236,11 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
s_linked_hash_map_put = env->GetMethodID(
|
s_linked_hash_map_put = env->GetMethodID(
|
||||||
s_linked_hash_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
s_linked_hash_map_class, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
|
||||||
|
|
||||||
|
const jclass compress_cb_class =
|
||||||
|
env->FindClass("org/dolphinemu/dolphinemu/utils/CompressCallback");
|
||||||
|
s_compress_cb_class = reinterpret_cast<jclass>(env->NewGlobalRef(compress_cb_class));
|
||||||
|
s_compress_cb_run = env->GetMethodID(s_compress_cb_class, "run", "(Ljava/lang/String;F)Z");
|
||||||
|
|
||||||
return JNI_VERSION;
|
return JNI_VERSION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,6 +257,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
|
||||||
env->DeleteGlobalRef(s_linked_hash_map_class);
|
env->DeleteGlobalRef(s_linked_hash_map_class);
|
||||||
env->DeleteGlobalRef(s_ini_file_class);
|
env->DeleteGlobalRef(s_ini_file_class);
|
||||||
env->DeleteGlobalRef(s_ini_file_section_class);
|
env->DeleteGlobalRef(s_ini_file_section_class);
|
||||||
|
env->DeleteGlobalRef(s_compress_cb_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -38,4 +38,7 @@ jclass GetIniFileSectionClass();
|
||||||
jfieldID GetIniFileSectionPointer();
|
jfieldID GetIniFileSectionPointer();
|
||||||
jmethodID GetIniFileSectionConstructor();
|
jmethodID GetIniFileSectionConstructor();
|
||||||
|
|
||||||
|
jclass GetCompressCallbackClass();
|
||||||
|
jmethodID GetCompressCallbackRun();
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
#include "Common/IniFile.h"
|
#include "Common/IniFile.h"
|
||||||
#include "Common/Logging/LogManager.h"
|
#include "Common/Logging/LogManager.h"
|
||||||
#include "Common/MsgHandler.h"
|
#include "Common/MsgHandler.h"
|
||||||
|
#include "Common/ScopeGuard.h"
|
||||||
#include "Common/Version.h"
|
#include "Common/Version.h"
|
||||||
#include "Common/WindowSystemInfo.h"
|
#include "Common/WindowSystemInfo.h"
|
||||||
|
|
||||||
|
@ -668,7 +669,7 @@ JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_InstallW
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(
|
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertDiscImage(
|
||||||
JNIEnv* env, jobject obj, jstring jInPath, jstring jOutPath, jint jPlatform, jint jFormat,
|
JNIEnv* env, jobject obj, jstring jInPath, jstring jOutPath, jint jPlatform, jint jFormat,
|
||||||
jint jBlockSize, jint jCompression, jint jCompressionLevel, jboolean jScrub)
|
jint jBlockSize, jint jCompression, jint jCompressionLevel, jboolean jScrub, jobject jCallback)
|
||||||
{
|
{
|
||||||
const std::string in_path = GetJString(env, jInPath);
|
const std::string in_path = GetJString(env, jInPath);
|
||||||
const std::string out_path = GetJString(env, jOutPath);
|
const std::string out_path = GetJString(env, jOutPath);
|
||||||
|
@ -687,7 +688,14 @@ JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ConvertD
|
||||||
if (!blob_reader)
|
if (!blob_reader)
|
||||||
return static_cast<jboolean>(false);
|
return static_cast<jboolean>(false);
|
||||||
|
|
||||||
const auto callback = [](const std::string& text, float percent) { return true; };
|
jobject jCallbackGlobal = env->NewGlobalRef(jCallback);
|
||||||
|
Common::ScopeGuard scope_guard([jCallbackGlobal, env] { env->DeleteGlobalRef(jCallbackGlobal); });
|
||||||
|
|
||||||
|
const auto callback = [&jCallbackGlobal](const std::string& text, float completion) {
|
||||||
|
JNIEnv* env = IDCache::GetEnvForThread();
|
||||||
|
return static_cast<bool>(env->CallBooleanMethod(
|
||||||
|
jCallbackGlobal, IDCache::GetCompressCallbackRun(), ToJString(env, text), completion));
|
||||||
|
};
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue