mirror of
https://github.com/PabloMK7/citra.git
synced 2025-09-08 20:00:04 +00:00
Add Android support
This commit is contained in:
parent
78c48a46e0
commit
7412586f5b
6 changed files with 125 additions and 15 deletions
|
@ -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,16 +376,23 @@ 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(
|
||||
CitraApplication.appContext.resources.getString(R.string.redump_games),
|
||||
Html.FROM_HTML_MODE_LEGACY
|
||||
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
|
||||
)
|
||||
)
|
||||
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
|
||||
|
@ -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 ->
|
||||
coreErrorAlertResult = false
|
||||
}.show()
|
||||
}
|
||||
dialog.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
|
||||
coreErrorAlertResult = false
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
window->TryPresenting();
|
||||
if (window) {
|
||||
window->TryPresenting();
|
||||
}
|
||||
}
|
||||
|
||||
void JNICALL Java_org_citra_citra_1emu_NativeLibrary_initializeGpuDriver(
|
||||
|
|
9
src/android/app/src/main/res/drawable/ic_network.xml
Normal file
9
src/android/app/src/main/res/drawable/ic_network.xml
Normal 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>
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue