Add Android support

This commit is contained in:
PabloMK7 2024-05-12 01:34:34 +02:00
parent 78c48a46e0
commit 7412586f5b
6 changed files with 125 additions and 15 deletions

View file

@ -183,13 +183,13 @@ object NativeLibrary {
private var coreErrorAlertResult = false
private val coreErrorAlertLock = Object()
private fun onCoreErrorImpl(title: String, message: String) {
private fun onCoreErrorImpl(title: String, message: String, canContinue: Boolean) {
val emulationActivity = sEmulationActivity.get()
if (emulationActivity == null) {
Log.error("[NativeLibrary] EmulationActivity not present")
return
}
val fragment = CoreErrorDialogFragment.newInstance(title, message)
val fragment = CoreErrorDialogFragment.newInstance(title, message, canContinue)
fragment.show(emulationActivity.supportFragmentManager, CoreErrorDialogFragment.TAG)
}
@ -207,6 +207,7 @@ object NativeLibrary {
}
val title: String
val message: String
val canContinue: Boolean
when (error) {
CoreError.ErrorSystemFiles -> {
title = emulationActivity.getString(R.string.system_archive_not_found)
@ -214,16 +215,25 @@ object NativeLibrary {
R.string.system_archive_not_found_message,
details.ifEmpty { emulationActivity.getString(R.string.system_archive_general) }
)
canContinue = true
}
CoreError.ErrorSavestate -> {
title = emulationActivity.getString(R.string.save_load_error)
message = details
canContinue = true
}
CoreError.ErrorArticDisconnected -> {
title = emulationActivity.getString(R.string.artic_base)
message = emulationActivity.getString(R.string.artic_server_comm_error)
canContinue = false
}
CoreError.ErrorUnknown -> {
title = emulationActivity.getString(R.string.fatal_error)
message = emulationActivity.getString(R.string.fatal_error_message)
canContinue = true
}
else -> {
@ -232,7 +242,7 @@ object NativeLibrary {
}
// Show the AlertDialog on the main thread.
emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) })
emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message, canContinue) })
// Wait for the lock to notify that it is complete.
synchronized(coreErrorAlertLock) {
@ -346,6 +356,11 @@ object NativeLibrary {
return
}
if (resultCode == EmulationErrorDialogFragment.ShutdownRequested) {
emulationActivity.finish()
return
}
emulationActivity.runOnUiThread {
EmulationErrorDialogFragment.newInstance(resultCode).showNow(
emulationActivity.supportFragmentManager,
@ -361,14 +376,21 @@ object NativeLibrary {
emulationActivity = requireActivity() as EmulationActivity
var captionId = R.string.loader_error_invalid_format
if (requireArguments().getInt(RESULT_CODE) == ErrorLoader_ErrorEncrypted) {
val result = requireArguments().getInt(RESULT_CODE)
if (result == ErrorLoader_ErrorEncrypted) {
captionId = R.string.loader_error_encrypted
}
if (result == ErrorArticDisconnected) {
captionId = R.string.artic_base
}
val alert = MaterialAlertDialogBuilder(requireContext())
.setTitle(captionId)
.setMessage(
Html.fromHtml(
if (result == ErrorArticDisconnected)
CitraApplication.appContext.resources.getString(R.string.artic_server_comm_error)
else
CitraApplication.appContext.resources.getString(R.string.redump_games),
Html.FROM_HTML_MODE_LEGACY
)
@ -398,7 +420,10 @@ object NativeLibrary {
const val ErrorLoader = 4
const val ErrorLoader_ErrorEncrypted = 5
const val ErrorLoader_ErrorInvalidFormat = 6
const val ErrorSystemFiles = 7
const val ErrorLoader_ErrorGBATitle = 7
const val ErrorSystemFiles = 8
const val ErrorSavestate = 9
const val ErrorArticDisconnected = 10
const val ShutdownRequested = 11
const val ErrorUnknown = 12
@ -619,6 +644,7 @@ object NativeLibrary {
enum class CoreError {
ErrorSystemFiles,
ErrorSavestate,
ErrorArticDisconnected,
ErrorUnknown
}
@ -633,23 +659,33 @@ object NativeLibrary {
}
class CoreErrorDialogFragment : DialogFragment() {
private var userChosen = false
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val title = requireArguments().getString(TITLE)
val message = requireArguments().getString(MESSAGE)
return MaterialAlertDialogBuilder(requireContext())
val canContinue = requireArguments().getBoolean(CAN_CONTINUE)
val dialog = MaterialAlertDialogBuilder(requireContext())
.setTitle(title)
.setMessage(message)
.setPositiveButton(R.string.continue_button) { _: DialogInterface?, _: Int ->
if (canContinue) {
dialog.setPositiveButton(R.string.continue_button) { _: DialogInterface?, _: Int ->
coreErrorAlertResult = true
userChosen = true
}
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
}
dialog.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
coreErrorAlertResult = false
}.show()
userChosen = true
}
return dialog.show()
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
coreErrorAlertResult = true
val canContinue = requireArguments().getBoolean(CAN_CONTINUE)
if (!userChosen) {
coreErrorAlertResult = canContinue
}
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
}
@ -658,12 +694,14 @@ object NativeLibrary {
const val TITLE = "title"
const val MESSAGE = "message"
const val CAN_CONTINUE = "canContinue"
fun newInstance(title: String, message: String): CoreErrorDialogFragment {
fun newInstance(title: String, message: String, canContinue: Boolean): CoreErrorDialogFragment {
val frag = CoreErrorDialogFragment()
val args = Bundle()
args.putString(TITLE, title)
args.putString(MESSAGE, message)
args.putBoolean(CAN_CONTINUE, canContinue)
frag.arguments = args
return frag
}

View file

@ -16,6 +16,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
@ -23,14 +24,19 @@ import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import androidx.preference.PreferenceManager
import androidx.recyclerview.widget.GridLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.transition.MaterialSharedAxis
import org.citra.citra_emu.CitraApplication
import org.citra.citra_emu.HomeNavigationDirections
import org.citra.citra_emu.R
import org.citra.citra_emu.adapters.HomeSettingAdapter
import org.citra.citra_emu.databinding.DialogSoftwareKeyboardBinding
import org.citra.citra_emu.databinding.FragmentHomeSettingsBinding
import org.citra.citra_emu.features.settings.model.Settings
import org.citra.citra_emu.features.settings.model.StringSetting
import org.citra.citra_emu.features.settings.ui.SettingsActivity
import org.citra.citra_emu.features.settings.utils.SettingsFile
import org.citra.citra_emu.model.Game
import org.citra.citra_emu.model.HomeSetting
import org.citra.citra_emu.ui.main.MainActivity
import org.citra.citra_emu.utils.GameHelper
@ -76,6 +82,41 @@ class HomeSettingsFragment : Fragment() {
R.drawable.ic_settings,
{ SettingsActivity.launch(requireContext(), SettingsFile.FILE_NAME_CONFIG, "") }
),
HomeSetting(
R.string.artic_base_connect,
R.string.artic_base_connect_description,
R.drawable.ic_network,
{
val inflater = LayoutInflater.from(context)
val inputBinding = DialogSoftwareKeyboardBinding.inflate(inflater)
var textInputValue: String = ""
inputBinding.editTextInput.setText(textInputValue)
inputBinding.editTextInput.doOnTextChanged { text, _, _, _ ->
textInputValue = text.toString()
}
val dialog = context?.let {
MaterialAlertDialogBuilder(it)
.setView(inputBinding.root)
.setTitle(getString(R.string.artic_base_enter_address))
.setPositiveButton(android.R.string.ok) { _, _ ->
if (textInputValue.isNotEmpty()) {
val menu = Game(
title = getString(R.string.artic_base),
path = "articbase://$textInputValue",
filename = ""
)
val action =
HomeNavigationDirections.actionGlobalEmulationActivity(menu)
binding.root.findNavController().navigate(action)
}
}
.setNegativeButton(android.R.string.cancel) {_, _ -> }
.show()
}
}
),
HomeSetting(
R.string.system_files,
R.string.system_files_description,

View file

@ -82,6 +82,7 @@ static jobject ToJavaCoreError(Core::System::ResultStatus result) {
static const std::map<Core::System::ResultStatus, const char*> CoreErrorNameMap{
{Core::System::ResultStatus::ErrorSystemFiles, "ErrorSystemFiles"},
{Core::System::ResultStatus::ErrorSavestate, "ErrorSavestate"},
{Core::System::ResultStatus::ErrorArticDisconnected, "ErrorArticDisconnected"},
{Core::System::ResultStatus::ErrorUnknown, "ErrorUnknown"},
};
@ -178,6 +179,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
auto app_loader = Loader::GetLoader(filepath);
if (app_loader) {
app_loader->ReadProgramId(program_id);
system.RegisterAppLoaderEarly(app_loader);
GameSettings::LoadOverrides(program_id);
}
system.ApplySettings();
@ -231,6 +233,10 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
InputManager::NDKMotionHandler()->DisableSensors();
if (!HandleCoreError(result, system.GetStatusDetails())) {
// Frontend requests us to abort
// If the error was an Artic disconnect, return shutdown request.
if (result == Core::System::ResultStatus::ErrorArticDisconnected) {
return Core::System::ResultStatus::ShutdownRequested;
}
return result;
}
InputManager::NDKMotionHandler()->EnableSensors();
@ -314,7 +320,9 @@ void Java_org_citra_citra_1emu_NativeLibrary_doFrame([[maybe_unused]] JNIEnv* en
if (stop_run || pause_emulation) {
return;
}
if (window) {
window->TryPresenting();
}
}
void JNICALL Java_org_citra_citra_1emu_NativeLibrary_initializeGpuDriver(

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M200,840q-33,0 -56.5,-23.5T120,760q0,-33 23.5,-56.5T200,680q33,0 56.5,23.5T280,760q0,33 -23.5,56.5T200,840ZM680,840q0,-117 -44,-218.5T516,444q-76,-76 -177.5,-120T120,280v-120q142,0 265,53t216,146q93,93 146,216t53,265L680,840ZM440,840q0,-67 -25,-124.5T346,614q-44,-44 -101.5,-69T120,520v-120q92,0 171.5,34.5T431,529q60,60 94.5,139.5T560,840L440,840Z"/>
</vector>

View file

@ -657,4 +657,11 @@ Se esperan fallos gráficos temporales cuando ésta esté activado.</string>
<string name="november">Noviembre</string>
<string name="december">Diciembre</string>
<!-- Artic base -->
<string name="artic_server_comm_error">Fallo de comunicación con el servidor Artic Base. La emulación se detendrá.</string>
<string name="artic_base">Artic Base</string>
<string name="artic_base_connect">Conectar con Artic Base</string>
<string name="artic_base_connect_description">Conectar con una consola real que esté ejecutando un servidor Artic Base</string>
<string name="artic_base_enter_address">Introduce la dirección del servidor Artic Base</string>
</resources>

View file

@ -683,4 +683,11 @@
<string name="november">November</string>
<string name="december">December</string>
<!-- Artic base -->
<string name="artic_server_comm_error">Failed to communicate with the Artic Base server. Emulation will stop.</string>
<string name="artic_base">Artic Base</string>
<string name="artic_base_connect_description">Connect to a real console that is running an Artic Base server</string>
<string name="artic_base_connect">Connect to Artic Base</string>
<string name="artic_base_enter_address">Enter Artic Base server address</string>
</resources>