android: Convert NativeLibrary to Kotlin
parent
a827486391
commit
4d9011a8f0
@ -1,698 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2013 Dolphin Emulator Project
|
|
||||||
* Licensed under GPLv2+
|
|
||||||
* Refer to the license.txt file included.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.yuzu.yuzu_emu;
|
|
||||||
|
|
||||||
import android.app.Activity;
|
|
||||||
import android.app.Dialog;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
import android.content.res.Configuration;
|
|
||||||
import android.os.Bundle;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.method.LinkMovementMethod;
|
|
||||||
import android.view.Surface;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
|
||||||
import android.widget.FrameLayout;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.appcompat.app.AlertDialog;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.fragment.app.DialogFragment;
|
|
||||||
|
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
|
||||||
|
|
||||||
import org.yuzu.yuzu_emu.activities.EmulationActivity;
|
|
||||||
import org.yuzu.yuzu_emu.utils.DocumentsTree;
|
|
||||||
import org.yuzu.yuzu_emu.utils.EmulationMenuSettings;
|
|
||||||
import org.yuzu.yuzu_emu.utils.FileUtil;
|
|
||||||
import org.yuzu.yuzu_emu.utils.Log;
|
|
||||||
|
|
||||||
import java.lang.ref.WeakReference;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import static android.Manifest.permission.CAMERA;
|
|
||||||
import static android.Manifest.permission.RECORD_AUDIO;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class which contains methods that interact
|
|
||||||
* with the native side of the Citra code.
|
|
||||||
*/
|
|
||||||
public final class NativeLibrary {
|
|
||||||
/**
|
|
||||||
* Default controller id for each device
|
|
||||||
*/
|
|
||||||
public static final int Player1Device = 0;
|
|
||||||
public static final int Player2Device = 1;
|
|
||||||
public static final int Player3Device = 2;
|
|
||||||
public static final int Player4Device = 3;
|
|
||||||
public static final int Player5Device = 4;
|
|
||||||
public static final int Player6Device = 5;
|
|
||||||
public static final int Player7Device = 6;
|
|
||||||
public static final int Player8Device = 7;
|
|
||||||
public static final int ConsoleDevice = 8;
|
|
||||||
public static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null);
|
|
||||||
|
|
||||||
private static boolean alertResult = false;
|
|
||||||
private static String alertPromptResult = "";
|
|
||||||
private static int alertPromptButton = 0;
|
|
||||||
private static final Object alertPromptLock = new Object();
|
|
||||||
private static boolean alertPromptInProgress = false;
|
|
||||||
private static String alertPromptCaption = "";
|
|
||||||
private static int alertPromptButtonConfig = 0;
|
|
||||||
private static EditText alertPromptEditText = null;
|
|
||||||
|
|
||||||
static {
|
|
||||||
try {
|
|
||||||
System.loadLibrary("yuzu-android");
|
|
||||||
} catch (UnsatisfiedLinkError ex) {
|
|
||||||
Log.error("[NativeLibrary] " + ex.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private NativeLibrary() {
|
|
||||||
// Disallows instantiation.
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int openContentUri(String path, String openmode) {
|
|
||||||
if (DocumentsTree.isNativePath(path)) {
|
|
||||||
return YuzuApplication.documentsTree.openContentUri(path, openmode);
|
|
||||||
}
|
|
||||||
return FileUtil.openContentUri(YuzuApplication.getAppContext(), path, openmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getSize(String path) {
|
|
||||||
if (DocumentsTree.isNativePath(path)) {
|
|
||||||
return YuzuApplication.documentsTree.getFileSize(path);
|
|
||||||
}
|
|
||||||
return FileUtil.getFileSize(YuzuApplication.getAppContext(), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles button press events for a gamepad.
|
|
||||||
*
|
|
||||||
* @param Device The input descriptor of the gamepad.
|
|
||||||
* @param Button Key code identifying which button was pressed.
|
|
||||||
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
|
||||||
* @return If we handled the button press.
|
|
||||||
*/
|
|
||||||
public static native boolean onGamePadButtonEvent(int Device, int Button, int Action);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles joystick movement events.
|
|
||||||
*
|
|
||||||
* @param Device The device ID of the gamepad.
|
|
||||||
* @param Axis The axis ID
|
|
||||||
* @param x_axis The value of the x-axis represented by the given ID.
|
|
||||||
* @param y_axis The value of the y-axis represented by the given ID.
|
|
||||||
*/
|
|
||||||
public static native boolean onGamePadJoystickEvent(int Device, int Axis, float x_axis, float y_axis);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles motion events.
|
|
||||||
*
|
|
||||||
* @param delta_timestamp The finger id corresponding to this event
|
|
||||||
* @param gyro_x,gyro_y,gyro_z The value of the accelerometer sensor.
|
|
||||||
* @param accel_x,accel_y,accel_z The value of the y-axis
|
|
||||||
*/
|
|
||||||
|
|
||||||
public static native boolean onGamePadMotionEvent(int Device, long delta_timestamp, float gyro_x, float gyro_y,
|
|
||||||
float gyro_z, float accel_x, float accel_y, float accel_z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signals and load a nfc tag
|
|
||||||
*
|
|
||||||
* @param data Byte array containing all the data from a nfc tag
|
|
||||||
*/
|
|
||||||
public static native boolean onReadNfcTag(byte[] data);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes current loaded nfc tag
|
|
||||||
*/
|
|
||||||
public static native boolean onRemoveNfcTag();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles touch press events.
|
|
||||||
*
|
|
||||||
* @param finger_id The finger id corresponding to this event
|
|
||||||
* @param x_axis The value of the x-axis.
|
|
||||||
* @param y_axis The value of the y-axis.
|
|
||||||
*/
|
|
||||||
public static native void onTouchPressed(int finger_id, float x_axis, float y_axis);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles touch movement.
|
|
||||||
*
|
|
||||||
* @param x_axis The value of the instantaneous x-axis.
|
|
||||||
* @param y_axis The value of the instantaneous y-axis.
|
|
||||||
*/
|
|
||||||
public static native void onTouchMoved(int finger_id, float x_axis, float y_axis);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles touch release events.
|
|
||||||
*
|
|
||||||
* @param finger_id The finger id corresponding to this event
|
|
||||||
*/
|
|
||||||
public static native void onTouchReleased(int finger_id);
|
|
||||||
|
|
||||||
public static native void ReloadSettings();
|
|
||||||
|
|
||||||
public static native String GetUserSetting(String gameID, String Section, String Key);
|
|
||||||
|
|
||||||
public static native void SetUserSetting(String gameID, String Section, String Key, String Value);
|
|
||||||
|
|
||||||
public static native void InitGameIni(String gameID);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the embedded icon within the given ROM.
|
|
||||||
*
|
|
||||||
* @param filename the file path to the ROM.
|
|
||||||
* @return a byte array containing the JPEG data for the icon.
|
|
||||||
*/
|
|
||||||
public static native byte[] GetIcon(String filename);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the embedded title of the given ISO/ROM.
|
|
||||||
*
|
|
||||||
* @param filename The file path to the ISO/ROM.
|
|
||||||
* @return the embedded title of the ISO/ROM.
|
|
||||||
*/
|
|
||||||
public static native String GetTitle(String filename);
|
|
||||||
|
|
||||||
public static native String GetDescription(String filename);
|
|
||||||
|
|
||||||
public static native String GetGameId(String filename);
|
|
||||||
|
|
||||||
public static native String GetRegions(String filename);
|
|
||||||
|
|
||||||
public static native String GetCompany(String filename);
|
|
||||||
|
|
||||||
public static native String GetGitRevision();
|
|
||||||
|
|
||||||
public static native void SetAppDirectory(String directory);
|
|
||||||
|
|
||||||
public static native void InitializeGpuDriver(String hookLibDir, String customDriverDir, String customDriverName, String fileRedirectDir);
|
|
||||||
|
|
||||||
public static native boolean ReloadKeys();
|
|
||||||
|
|
||||||
public static native void InitializeEmulation();
|
|
||||||
|
|
||||||
public static native int DefaultCPUCore();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins emulation.
|
|
||||||
*/
|
|
||||||
public static native void Run(String path);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Begins emulation from the specified savestate.
|
|
||||||
*/
|
|
||||||
public static native void Run(String path, String savestatePath, boolean deleteSavestate);
|
|
||||||
|
|
||||||
// Surface Handling
|
|
||||||
public static native void SurfaceChanged(Surface surf);
|
|
||||||
|
|
||||||
public static native void SurfaceDestroyed();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unpauses emulation from a paused state.
|
|
||||||
*/
|
|
||||||
public static native void UnPauseEmulation();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pauses emulation.
|
|
||||||
*/
|
|
||||||
public static native void PauseEmulation();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stops emulation.
|
|
||||||
*/
|
|
||||||
public static native void StopEmulation();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the in-memory ROM metadata cache.
|
|
||||||
*/
|
|
||||||
public static native void ResetRomMetadata();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if emulation is running (or is paused).
|
|
||||||
*/
|
|
||||||
public static native boolean IsRunning();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the performance stats for the current game
|
|
||||||
**/
|
|
||||||
public static native double[] GetPerfStats();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notifies the core emulation that the orientation has changed.
|
|
||||||
*/
|
|
||||||
public static native void NotifyOrientationChange(int layout_option, int rotation);
|
|
||||||
|
|
||||||
public enum CoreError {
|
|
||||||
ErrorSystemFiles,
|
|
||||||
ErrorSavestate,
|
|
||||||
ErrorUnknown,
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean coreErrorAlertResult = false;
|
|
||||||
private static final Object coreErrorAlertLock = new Object();
|
|
||||||
|
|
||||||
public static class CoreErrorDialogFragment extends DialogFragment {
|
|
||||||
static CoreErrorDialogFragment newInstance(String title, String message) {
|
|
||||||
CoreErrorDialogFragment frag = new CoreErrorDialogFragment();
|
|
||||||
Bundle args = new Bundle();
|
|
||||||
args.putString("title", title);
|
|
||||||
args.putString("message", message);
|
|
||||||
frag.setArguments(args);
|
|
||||||
return frag;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
|
||||||
final Activity emulationActivity = Objects.requireNonNull(getActivity());
|
|
||||||
|
|
||||||
final String title = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("title"));
|
|
||||||
final String message = Objects.requireNonNull(Objects.requireNonNull(getArguments()).getString("message"));
|
|
||||||
|
|
||||||
return new MaterialAlertDialogBuilder(emulationActivity)
|
|
||||||
.setTitle(title)
|
|
||||||
.setMessage(message)
|
|
||||||
.setPositiveButton(R.string.continue_button, (dialog, which) -> {
|
|
||||||
coreErrorAlertResult = true;
|
|
||||||
synchronized (coreErrorAlertLock) {
|
|
||||||
coreErrorAlertLock.notify();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(R.string.abort_button, (dialog, which) -> {
|
|
||||||
coreErrorAlertResult = false;
|
|
||||||
synchronized (coreErrorAlertLock) {
|
|
||||||
coreErrorAlertLock.notify();
|
|
||||||
}
|
|
||||||
}).setOnDismissListener(dialog -> {
|
|
||||||
coreErrorAlertResult = true;
|
|
||||||
synchronized (coreErrorAlertLock) {
|
|
||||||
coreErrorAlertLock.notify();
|
|
||||||
}
|
|
||||||
}).create();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void OnCoreErrorImpl(String title, String message) {
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.error("[NativeLibrary] EmulationActivity not present");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
CoreErrorDialogFragment fragment = CoreErrorDialogFragment.newInstance(title, message);
|
|
||||||
fragment.show(emulationActivity.getSupportFragmentManager(), "coreError");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Handles a core error.
|
|
||||||
*
|
|
||||||
* @return true: continue; false: abort
|
|
||||||
*/
|
|
||||||
public static boolean OnCoreError(CoreError error, String details) {
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.error("[NativeLibrary] EmulationActivity not present");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
String title, message;
|
|
||||||
switch (error) {
|
|
||||||
case ErrorSystemFiles: {
|
|
||||||
title = emulationActivity.getString(R.string.system_archive_not_found);
|
|
||||||
message = emulationActivity.getString(R.string.system_archive_not_found_message, details.isEmpty() ? emulationActivity.getString(R.string.system_archive_general) : details);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ErrorSavestate: {
|
|
||||||
title = emulationActivity.getString(R.string.save_load_error);
|
|
||||||
message = details;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ErrorUnknown: {
|
|
||||||
title = emulationActivity.getString(R.string.fatal_error);
|
|
||||||
message = emulationActivity.getString(R.string.fatal_error_message);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the AlertDialog on the main thread.
|
|
||||||
emulationActivity.runOnUiThread(() -> OnCoreErrorImpl(title, message));
|
|
||||||
|
|
||||||
// Wait for the lock to notify that it is complete.
|
|
||||||
synchronized (coreErrorAlertLock) {
|
|
||||||
try {
|
|
||||||
coreErrorAlertLock.wait();
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return coreErrorAlertResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isPortraitMode() {
|
|
||||||
return YuzuApplication.getAppContext().getResources().getConfiguration().orientation ==
|
|
||||||
Configuration.ORIENTATION_PORTRAIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int landscapeScreenLayout() {
|
|
||||||
return EmulationMenuSettings.getLandscapeScreenLayout();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean displayAlertMsg(final String caption, final String text,
|
|
||||||
final boolean yesNo) {
|
|
||||||
Log.error("[NativeLibrary] Alert: " + text);
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
boolean result = false;
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert.");
|
|
||||||
} else {
|
|
||||||
// Create object used for waiting.
|
|
||||||
final Object lock = new Object();
|
|
||||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
|
|
||||||
.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) {
|
|
||||||
builder
|
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
alertResult = false;
|
|
||||||
|
|
||||||
builder
|
|
||||||
.setPositiveButton(android.R.string.yes, (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
alertResult = true;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setNegativeButton(android.R.string.no, (dialog, whichButton) ->
|
|
||||||
{
|
|
||||||
alertResult = false;
|
|
||||||
dialog.dismiss();
|
|
||||||
synchronized (lock) {
|
|
||||||
lock.notify();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the AlertDialog on the main thread.
|
|
||||||
emulationActivity.runOnUiThread(builder::show);
|
|
||||||
|
|
||||||
// Wait for the lock to notify that it is complete.
|
|
||||||
synchronized (lock) {
|
|
||||||
try {
|
|
||||||
lock.wait();
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (yesNo)
|
|
||||||
result = alertResult;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void retryDisplayAlertPrompt() {
|
|
||||||
if (!alertPromptInProgress) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
displayAlertPromptImpl(alertPromptCaption, alertPromptEditText.getText().toString(), alertPromptButtonConfig).show();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String displayAlertPrompt(String caption, String text, int buttonConfig) {
|
|
||||||
alertPromptCaption = caption;
|
|
||||||
alertPromptButtonConfig = buttonConfig;
|
|
||||||
alertPromptInProgress = true;
|
|
||||||
|
|
||||||
// Show the AlertDialog on the main thread
|
|
||||||
sEmulationActivity.get().runOnUiThread(() -> displayAlertPromptImpl(alertPromptCaption, text, alertPromptButtonConfig).show());
|
|
||||||
|
|
||||||
// Wait for the lock to notify that it is complete
|
|
||||||
synchronized (alertPromptLock) {
|
|
||||||
try {
|
|
||||||
alertPromptLock.wait();
|
|
||||||
} catch (Exception e) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alertPromptInProgress = false;
|
|
||||||
|
|
||||||
return alertPromptResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static MaterialAlertDialogBuilder displayAlertPromptImpl(String caption, String text, int buttonConfig) {
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
alertPromptResult = "";
|
|
||||||
alertPromptButton = 0;
|
|
||||||
|
|
||||||
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
|
|
||||||
params.leftMargin = params.rightMargin = YuzuApplication.getAppContext().getResources().getDimensionPixelSize(R.dimen.dialog_margin);
|
|
||||||
|
|
||||||
// Set up the input
|
|
||||||
alertPromptEditText = new EditText(YuzuApplication.getAppContext());
|
|
||||||
alertPromptEditText.setText(text);
|
|
||||||
alertPromptEditText.setSingleLine();
|
|
||||||
alertPromptEditText.setLayoutParams(params);
|
|
||||||
|
|
||||||
FrameLayout container = new FrameLayout(emulationActivity);
|
|
||||||
container.addView(alertPromptEditText);
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
|
|
||||||
.setTitle(caption)
|
|
||||||
.setView(container)
|
|
||||||
.setPositiveButton(android.R.string.ok, (dialogInterface, i) ->
|
|
||||||
{
|
|
||||||
alertPromptButton = buttonConfig;
|
|
||||||
alertPromptResult = alertPromptEditText.getText().toString();
|
|
||||||
synchronized (alertPromptLock) {
|
|
||||||
alertPromptLock.notifyAll();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.setOnDismissListener(dialogInterface ->
|
|
||||||
{
|
|
||||||
alertPromptResult = "";
|
|
||||||
synchronized (alertPromptLock) {
|
|
||||||
alertPromptLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (buttonConfig > 0) {
|
|
||||||
builder.setNegativeButton(android.R.string.cancel, (dialogInterface, i) ->
|
|
||||||
{
|
|
||||||
alertPromptResult = "";
|
|
||||||
synchronized (alertPromptLock) {
|
|
||||||
alertPromptLock.notifyAll();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int alertPromptButton() {
|
|
||||||
return alertPromptButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void exitEmulationActivity(int resultCode) {
|
|
||||||
final int Success = 0;
|
|
||||||
final int ErrorNotInitialized = 1;
|
|
||||||
final int ErrorGetLoader = 2;
|
|
||||||
final int ErrorSystemFiles = 3;
|
|
||||||
final int ErrorSharedFont = 4;
|
|
||||||
final int ErrorVideoCore = 5;
|
|
||||||
final int ErrorUnknown = 6;
|
|
||||||
final int ErrorLoader = 7;
|
|
||||||
|
|
||||||
int captionId;
|
|
||||||
int descriptionId;
|
|
||||||
switch (resultCode) {
|
|
||||||
case ErrorVideoCore:
|
|
||||||
captionId = R.string.loader_error_video_core;
|
|
||||||
descriptionId = R.string.loader_error_video_core_description;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
captionId = R.string.loader_error_encrypted;
|
|
||||||
descriptionId = R.string.loader_error_encrypted_roms_description;
|
|
||||||
if (!ReloadKeys()) {
|
|
||||||
descriptionId = R.string.loader_error_encrypted_keys_description;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.warning("[NativeLibrary] EmulationActivity is null, can't exit.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(emulationActivity)
|
|
||||||
.setTitle(captionId)
|
|
||||||
.setMessage(Html.fromHtml(emulationActivity.getString(descriptionId), Html.FROM_HTML_MODE_LEGACY))
|
|
||||||
.setPositiveButton(android.R.string.ok, (dialog, whichButton) -> emulationActivity.finish())
|
|
||||||
.setOnDismissListener(dialogInterface -> emulationActivity.finish());
|
|
||||||
emulationActivity.runOnUiThread(() -> {
|
|
||||||
AlertDialog alert = builder.create();
|
|
||||||
alert.show();
|
|
||||||
((TextView) alert.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void setEmulationActivity(EmulationActivity emulationActivity) {
|
|
||||||
Log.verbose("[NativeLibrary] Registering EmulationActivity.");
|
|
||||||
sEmulationActivity = new WeakReference<>(emulationActivity);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void clearEmulationActivity() {
|
|
||||||
Log.verbose("[NativeLibrary] Unregistering EmulationActivity.");
|
|
||||||
|
|
||||||
sEmulationActivity.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Object cameraPermissionLock = new Object();
|
|
||||||
private static boolean cameraPermissionGranted = false;
|
|
||||||
public static final int REQUEST_CODE_NATIVE_CAMERA = 800;
|
|
||||||
|
|
||||||
public static boolean RequestCameraPermission() {
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.error("[NativeLibrary] EmulationActivity not present");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ContextCompat.checkSelfPermission(emulationActivity, CAMERA) == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// Permission already granted
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
emulationActivity.requestPermissions(new String[]{CAMERA}, REQUEST_CODE_NATIVE_CAMERA);
|
|
||||||
|
|
||||||
// Wait until result is returned
|
|
||||||
synchronized (cameraPermissionLock) {
|
|
||||||
try {
|
|
||||||
cameraPermissionLock.wait();
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cameraPermissionGranted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CameraPermissionResult(boolean granted) {
|
|
||||||
cameraPermissionGranted = granted;
|
|
||||||
synchronized (cameraPermissionLock) {
|
|
||||||
cameraPermissionLock.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Object micPermissionLock = new Object();
|
|
||||||
private static boolean micPermissionGranted = false;
|
|
||||||
public static final int REQUEST_CODE_NATIVE_MIC = 900;
|
|
||||||
|
|
||||||
public static boolean RequestMicPermission() {
|
|
||||||
final EmulationActivity emulationActivity = sEmulationActivity.get();
|
|
||||||
if (emulationActivity == null) {
|
|
||||||
Log.error("[NativeLibrary] EmulationActivity not present");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (ContextCompat.checkSelfPermission(emulationActivity, RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
|
|
||||||
// Permission already granted
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
emulationActivity.requestPermissions(new String[]{RECORD_AUDIO}, REQUEST_CODE_NATIVE_MIC);
|
|
||||||
|
|
||||||
// Wait until result is returned
|
|
||||||
synchronized (micPermissionLock) {
|
|
||||||
try {
|
|
||||||
micPermissionLock.wait();
|
|
||||||
} catch (InterruptedException ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return micPermissionGranted;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void MicPermissionResult(boolean granted) {
|
|
||||||
micPermissionGranted = granted;
|
|
||||||
synchronized (micPermissionLock) {
|
|
||||||
micPermissionLock.notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs the Citra version, Android version and, CPU.
|
|
||||||
*/
|
|
||||||
public static native void LogDeviceInfo();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits inline keyboard text. Called on input for buttons that result text.
|
|
||||||
* @param text Text to submit to the inline software keyboard implementation.
|
|
||||||
*/
|
|
||||||
public static native void SubmitInlineKeyboardText(String text);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits inline keyboard input. Used to indicate keys pressed that are not text.
|
|
||||||
* @param key_code Android Key Code associated with the keyboard input.
|
|
||||||
*/
|
|
||||||
public static native void SubmitInlineKeyboardInput(int key_code);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button type for use in onTouchEvent
|
|
||||||
*/
|
|
||||||
public static final class ButtonType {
|
|
||||||
public static final int BUTTON_A = 0;
|
|
||||||
public static final int BUTTON_B = 1;
|
|
||||||
public static final int BUTTON_X = 2;
|
|
||||||
public static final int BUTTON_Y = 3;
|
|
||||||
public static final int STICK_L = 4;
|
|
||||||
public static final int STICK_R = 5;
|
|
||||||
public static final int TRIGGER_L = 6;
|
|
||||||
public static final int TRIGGER_R = 7;
|
|
||||||
public static final int TRIGGER_ZL = 8;
|
|
||||||
public static final int TRIGGER_ZR = 9;
|
|
||||||
public static final int BUTTON_PLUS = 10;
|
|
||||||
public static final int BUTTON_MINUS = 11;
|
|
||||||
public static final int DPAD_LEFT = 12;
|
|
||||||
public static final int DPAD_UP = 13;
|
|
||||||
public static final int DPAD_RIGHT = 14;
|
|
||||||
public static final int DPAD_DOWN = 15;
|
|
||||||
public static final int BUTTON_SL = 16;
|
|
||||||
public static final int BUTTON_SR = 17;
|
|
||||||
public static final int BUTTON_HOME = 18;
|
|
||||||
public static final int BUTTON_CAPTURE = 19;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Stick type for use in onTouchEvent
|
|
||||||
*/
|
|
||||||
public static final class StickType {
|
|
||||||
public static final int STICK_L = 0;
|
|
||||||
public static final int STICK_R = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Button states
|
|
||||||
*/
|
|
||||||
public static final class ButtonState {
|
|
||||||
public static final int RELEASED = 0;
|
|
||||||
public static final int PRESSED = 1;
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,463 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
package org.yuzu.yuzu_emu
|
||||||
|
|
||||||
|
import android.app.Dialog
|
||||||
|
import android.content.DialogInterface
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.Html
|
||||||
|
import android.text.method.LinkMovementMethod
|
||||||
|
import android.view.Surface
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.TextView
|
||||||
|
import androidx.fragment.app.DialogFragment
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import org.yuzu.yuzu_emu.YuzuApplication.Companion.appContext
|
||||||
|
import org.yuzu.yuzu_emu.activities.EmulationActivity
|
||||||
|
import org.yuzu.yuzu_emu.utils.DocumentsTree.Companion.isNativePath
|
||||||
|
import org.yuzu.yuzu_emu.utils.FileUtil.getFileSize
|
||||||
|
import org.yuzu.yuzu_emu.utils.FileUtil.openContentUri
|
||||||
|
import org.yuzu.yuzu_emu.utils.Log.error
|
||||||
|
import org.yuzu.yuzu_emu.utils.Log.verbose
|
||||||
|
import org.yuzu.yuzu_emu.utils.Log.warning
|
||||||
|
import org.yuzu.yuzu_emu.utils.SerializableHelper.serializable
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class which contains methods that interact
|
||||||
|
* with the native side of the Yuzu code.
|
||||||
|
*/
|
||||||
|
object NativeLibrary {
|
||||||
|
/**
|
||||||
|
* Default controller id for each device
|
||||||
|
*/
|
||||||
|
const val Player1Device = 0
|
||||||
|
const val Player2Device = 1
|
||||||
|
const val Player3Device = 2
|
||||||
|
const val Player4Device = 3
|
||||||
|
const val Player5Device = 4
|
||||||
|
const val Player6Device = 5
|
||||||
|
const val Player7Device = 6
|
||||||
|
const val Player8Device = 7
|
||||||
|
const val ConsoleDevice = 8
|
||||||
|
|
||||||
|
var sEmulationActivity = WeakReference<EmulationActivity?>(null)
|
||||||
|
|
||||||
|
init {
|
||||||
|
try {
|
||||||
|
System.loadLibrary("yuzu-android")
|
||||||
|
} catch (ex: UnsatisfiedLinkError) {
|
||||||
|
error("[NativeLibrary] $ex")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun openContentUri(path: String?, openmode: String?): Int {
|
||||||
|
return if (isNativePath(path!!)) {
|
||||||
|
YuzuApplication.documentsTree!!.openContentUri(path, openmode)
|
||||||
|
} else openContentUri(appContext, path, openmode)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun getSize(path: String?): Long {
|
||||||
|
return if (isNativePath(path!!)) {
|
||||||
|
YuzuApplication.documentsTree!!.getFileSize(path)
|
||||||
|
} else getFileSize(appContext, path)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles button press events for a gamepad.
|
||||||
|
*
|
||||||
|
* @param Device The input descriptor of the gamepad.
|
||||||
|
* @param Button Key code identifying which button was pressed.
|
||||||
|
* @param Action Mask identifying which action is happening (button pressed down, or button released).
|
||||||
|
* @return If we handled the button press.
|
||||||
|
*/
|
||||||
|
external fun onGamePadButtonEvent(Device: Int, Button: Int, Action: Int): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles joystick movement events.
|
||||||
|
*
|
||||||
|
* @param Device The device ID of the gamepad.
|
||||||
|
* @param Axis The axis ID
|
||||||
|
* @param x_axis The value of the x-axis represented by the given ID.
|
||||||
|
* @param y_axis The value of the y-axis represented by the given ID.
|
||||||
|
*/
|
||||||
|
external fun onGamePadJoystickEvent(
|
||||||
|
Device: Int,
|
||||||
|
Axis: Int,
|
||||||
|
x_axis: Float,
|
||||||
|
y_axis: Float
|
||||||
|
): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles motion events.
|
||||||
|
*
|
||||||
|
* @param delta_timestamp The finger id corresponding to this event
|
||||||
|
* @param gyro_x,gyro_y,gyro_z The value of the accelerometer sensor.
|
||||||
|
* @param accel_x,accel_y,accel_z The value of the y-axis
|
||||||
|
*/
|
||||||
|
external fun onGamePadMotionEvent(
|
||||||
|
Device: Int,
|
||||||
|
delta_timestamp: Long,
|
||||||
|
gyro_x: Float,
|
||||||
|
gyro_y: Float,
|
||||||
|
gyro_z: Float,
|
||||||
|
accel_x: Float,
|
||||||
|
accel_y: Float,
|
||||||
|
accel_z: Float
|
||||||
|
): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signals and load a nfc tag
|
||||||
|
*
|
||||||
|
* @param data Byte array containing all the data from a nfc tag
|
||||||
|
*/
|
||||||
|
external fun onReadNfcTag(data: ByteArray?): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes current loaded nfc tag
|
||||||
|
*/
|
||||||
|
external fun onRemoveNfcTag(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles touch press events.
|
||||||
|
*
|
||||||
|
* @param finger_id The finger id corresponding to this event
|
||||||
|
* @param x_axis The value of the x-axis.
|
||||||
|
* @param y_axis The value of the y-axis.
|
||||||
|
*/
|
||||||
|
external fun onTouchPressed(finger_id: Int, x_axis: Float, y_axis: Float)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles touch movement.
|
||||||
|
*
|
||||||
|
* @param x_axis The value of the instantaneous x-axis.
|
||||||
|
* @param y_axis The value of the instantaneous y-axis.
|
||||||
|
*/
|
||||||
|
external fun onTouchMoved(finger_id: Int, x_axis: Float, y_axis: Float)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles touch release events.
|
||||||
|
*
|
||||||
|
* @param finger_id The finger id corresponding to this event
|
||||||
|
*/
|
||||||
|
external fun onTouchReleased(finger_id: Int)
|
||||||
|
|
||||||
|
external fun reloadSettings()
|
||||||
|
|
||||||
|
external fun getUserSetting(gameID: String?, Section: String?, Key: String?): String?
|
||||||
|
|
||||||
|
external fun setUserSetting(gameID: String?, Section: String?, Key: String?, Value: String?)
|
||||||
|
|
||||||
|
external fun initGameIni(gameID: String?)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the embedded icon within the given ROM.
|
||||||
|
*
|
||||||
|
* @param filename the file path to the ROM.
|
||||||
|
* @return a byte array containing the JPEG data for the icon.
|
||||||
|
*/
|
||||||
|
external fun getIcon(filename: String): ByteArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the embedded title of the given ISO/ROM.
|
||||||
|
*
|
||||||
|
* @param filename The file path to the ISO/ROM.
|
||||||
|
* @return the embedded title of the ISO/ROM.
|
||||||
|
*/
|
||||||
|
external fun getTitle(filename: String): String
|
||||||
|
|
||||||
|
external fun getDescription(filename: String): String
|
||||||
|
|
||||||
|
external fun getGameId(filename: String): String
|
||||||
|
|
||||||
|
external fun getRegions(filename: String): String
|
||||||
|
|
||||||
|
external fun getCompany(filename: String): String
|
||||||
|
|
||||||
|
external fun setAppDirectory(directory: String)
|
||||||
|
|
||||||
|
external fun initializeGpuDriver(
|
||||||
|
hookLibDir: String?,
|
||||||
|
customDriverDir: String?,
|
||||||
|
customDriverName: String?,
|
||||||
|
fileRedirectDir: String?
|
||||||
|
)
|
||||||
|
|
||||||
|
external fun reloadKeys(): Boolean
|
||||||
|
|
||||||
|
external fun initializeEmulation()
|
||||||
|
|
||||||
|
external fun defaultCPUCore(): Int
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begins emulation.
|
||||||
|
*/
|
||||||
|
external fun run(path: String?)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begins emulation from the specified savestate.
|
||||||
|
*/
|
||||||
|
external fun run(path: String?, savestatePath: String?, deleteSavestate: Boolean)
|
||||||
|
|
||||||
|
// Surface Handling
|
||||||
|
external fun surfaceChanged(surf: Surface?)
|
||||||
|
|
||||||
|
external fun surfaceDestroyed()
|
||||||
|
|
||||||
|
external fun doFrame()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpauses emulation from a paused state.
|
||||||
|
*/
|
||||||
|
external fun unPauseEmulation()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pauses emulation.
|
||||||
|
*/
|
||||||
|
external fun pauseEmulation()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops emulation.
|
||||||
|
*/
|
||||||
|
external fun stopEmulation()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the in-memory ROM metadata cache.
|
||||||
|
*/
|
||||||
|
external fun resetRomMetadata()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if emulation is running (or is paused).
|
||||||
|
*/
|
||||||
|
external fun isRunning(): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the performance stats for the current game
|
||||||
|
*/
|
||||||
|
external fun getPerfStats(): DoubleArray
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notifies the core emulation that the orientation has changed.
|
||||||
|
*/
|
||||||
|
external fun notifyOrientationChange(layout_option: Int, rotation: Int)
|
||||||
|
|
||||||
|
enum class CoreError {
|
||||||
|
ErrorSystemFiles,
|
||||||
|
ErrorSavestate,
|
||||||
|
ErrorUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
private var coreErrorAlertResult = false
|
||||||
|
private val coreErrorAlertLock = Object()
|
||||||
|
|
||||||
|
class CoreErrorDialogFragment : DialogFragment() {
|
||||||
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
|
val title = requireArguments().serializable<String>("title")
|
||||||
|
val message = requireArguments().serializable<String>("message")
|
||||||
|
|
||||||
|
return MaterialAlertDialogBuilder(requireActivity())
|
||||||
|
.setTitle(title)
|
||||||
|
.setMessage(message)
|
||||||
|
.setPositiveButton(R.string.continue_button, null)
|
||||||
|
.setNegativeButton(R.string.abort_button) { _: DialogInterface?, _: Int ->
|
||||||
|
coreErrorAlertResult = false
|
||||||
|
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
|
||||||
|
}
|
||||||
|
.create()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
|
coreErrorAlertResult = true
|
||||||
|
synchronized(coreErrorAlertLock) { coreErrorAlertLock.notify() }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun newInstance(title: String?, message: String?): CoreErrorDialogFragment {
|
||||||
|
val frag = CoreErrorDialogFragment()
|
||||||
|
val args = Bundle()
|
||||||
|
args.putString("title", title)
|
||||||
|
args.putString("message", message)
|
||||||
|
frag.arguments = args
|
||||||
|
return frag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onCoreErrorImpl(title: String, message: String) {
|
||||||
|
val emulationActivity = sEmulationActivity.get()
|
||||||
|
if (emulationActivity == null) {
|
||||||
|
error("[NativeLibrary] EmulationActivity not present")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val fragment = CoreErrorDialogFragment.newInstance(title, message)
|
||||||
|
fragment.show(emulationActivity.supportFragmentManager, "coreError")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles a core error.
|
||||||
|
*
|
||||||
|
* @return true: continue; false: abort
|
||||||
|
*/
|
||||||
|
fun onCoreError(error: CoreError?, details: String): Boolean {
|
||||||
|
val emulationActivity = sEmulationActivity.get()
|
||||||
|
if (emulationActivity == null) {
|
||||||
|
error("[NativeLibrary] EmulationActivity not present")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
val title: String
|
||||||
|
val message: String
|
||||||
|
when (error) {
|
||||||
|
CoreError.ErrorSystemFiles -> {
|
||||||
|
title = emulationActivity.getString(R.string.system_archive_not_found)
|
||||||
|
message = emulationActivity.getString(
|
||||||
|
R.string.system_archive_not_found_message,
|
||||||
|
details.ifEmpty { emulationActivity.getString(R.string.system_archive_general) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CoreError.ErrorSavestate -> {
|
||||||
|
title = emulationActivity.getString(R.string.save_load_error)
|
||||||
|
message = details
|
||||||
|
}
|
||||||
|
CoreError.ErrorUnknown -> {
|
||||||
|
title = emulationActivity.getString(R.string.fatal_error)
|
||||||
|
message = emulationActivity.getString(R.string.fatal_error_message)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show the AlertDialog on the main thread.
|
||||||
|
emulationActivity.runOnUiThread(Runnable { onCoreErrorImpl(title, message) })
|
||||||
|
|
||||||
|
// Wait for the lock to notify that it is complete.
|
||||||
|
synchronized(coreErrorAlertLock) { coreErrorAlertLock.wait() }
|
||||||
|
|
||||||
|
return coreErrorAlertResult
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun exitEmulationActivity(resultCode: Int) {
|
||||||
|
val Success = 0
|
||||||
|
val ErrorNotInitialized = 1
|
||||||
|
val ErrorGetLoader = 2
|
||||||
|
val ErrorSystemFiles = 3
|
||||||
|
val ErrorSharedFont = 4
|
||||||
|
val ErrorVideoCore = 5
|
||||||
|
val ErrorUnknown = 6
|
||||||
|
val ErrorLoader = 7
|
||||||
|
|
||||||
|
val captionId: Int
|
||||||
|
var descriptionId: Int
|
||||||
|
when (resultCode) {
|
||||||
|
ErrorVideoCore -> {
|
||||||
|
captionId = R.string.loader_error_video_core
|
||||||
|
descriptionId = R.string.loader_error_video_core_description
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
captionId = R.string.loader_error_encrypted
|
||||||
|
descriptionId = R.string.loader_error_encrypted_roms_description
|
||||||
|
if (!reloadKeys()) {
|
||||||
|
descriptionId = R.string.loader_error_encrypted_keys_description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val emulationActivity = sEmulationActivity.get()
|
||||||
|
if (emulationActivity == null) {
|
||||||
|
warning("[NativeLibrary] EmulationActivity is null, can't exit.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val builder = MaterialAlertDialogBuilder(emulationActivity)
|
||||||
|
.setTitle(captionId)
|
||||||
|
.setMessage(
|
||||||
|
Html.fromHtml(
|
||||||
|
emulationActivity.getString(descriptionId),
|
||||||
|
Html.FROM_HTML_MODE_LEGACY
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> emulationActivity.finish() }
|
||||||
|
.setOnDismissListener { emulationActivity.finish() }
|
||||||
|
emulationActivity.runOnUiThread {
|
||||||
|
val alert = builder.create()
|
||||||
|
alert.show()
|
||||||
|
(alert.findViewById<View>(android.R.id.message) as TextView).movementMethod =
|
||||||
|
LinkMovementMethod.getInstance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEmulationActivity(emulationActivity: EmulationActivity?) {
|
||||||
|
verbose("[NativeLibrary] Registering EmulationActivity.")
|
||||||
|
sEmulationActivity = WeakReference(emulationActivity)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun clearEmulationActivity() {
|
||||||
|
verbose("[NativeLibrary] Unregistering EmulationActivity.")
|
||||||
|
sEmulationActivity.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs the Yuzu version, Android version and, CPU.
|
||||||
|
*/
|
||||||
|
external fun logDeviceInfo()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits inline keyboard text. Called on input for buttons that result text.
|
||||||
|
* @param text Text to submit to the inline software keyboard implementation.
|
||||||
|
*/
|
||||||
|
external fun submitInlineKeyboardText(text: String?)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submits inline keyboard input. Used to indicate keys pressed that are not text.
|
||||||
|
* @param key_code Android Key Code associated with the keyboard input.
|
||||||
|
*/
|
||||||
|
external fun submitInlineKeyboardInput(key_code: Int)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button type for use in onTouchEvent
|
||||||
|
*/
|
||||||
|
object ButtonType {
|
||||||
|
const val BUTTON_A = 0
|
||||||
|
const val BUTTON_B = 1
|
||||||
|
const val BUTTON_X = 2
|
||||||
|
const val BUTTON_Y = 3
|
||||||
|
const val STICK_L = 4
|
||||||
|
const val STICK_R = 5
|
||||||
|
const val TRIGGER_L = 6
|
||||||
|
const val TRIGGER_R = 7
|
||||||
|
const val TRIGGER_ZL = 8
|
||||||
|
const val TRIGGER_ZR = 9
|
||||||
|
const val BUTTON_PLUS = 10
|
||||||
|
const val BUTTON_MINUS = 11
|
||||||
|
const val DPAD_LEFT = 12
|
||||||
|
const val DPAD_UP = 13
|
||||||
|
const val DPAD_RIGHT = 14
|
||||||
|
const val DPAD_DOWN = 15
|
||||||
|
const val BUTTON_SL = 16
|
||||||
|
const val BUTTON_SR = 17
|
||||||
|
const val BUTTON_HOME = 18
|
||||||
|
const val BUTTON_CAPTURE = 19
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stick type for use in onTouchEvent
|
||||||
|
*/
|
||||||
|
object StickType {
|
||||||
|
const val STICK_L = 0
|
||||||
|
const val STICK_R = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Button states
|
||||||
|
*/
|
||||||
|
object ButtonState {
|
||||||
|
const val RELEASED = 0
|
||||||
|
const val PRESSED = 1
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue