mirror of https://git.suyu.dev/suyu/suyu
android: Convert NativeLibrary to Kotlin
This commit is contained in:
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ class YuzuApplication : Application() {
|
||||||
documentsTree = DocumentsTree()
|
documentsTree = DocumentsTree()
|
||||||
DirectoryInitialization.start(applicationContext)
|
DirectoryInitialization.start(applicationContext)
|
||||||
GpuDriverHelper.initializeDriverParameters(applicationContext)
|
GpuDriverHelper.initializeDriverParameters(applicationContext)
|
||||||
NativeLibrary.LogDeviceInfo()
|
NativeLibrary.logDeviceInfo()
|
||||||
|
|
||||||
// TODO(bunnei): Disable notifications until we support app suspension.
|
// TODO(bunnei): Disable notifications until we support app suspension.
|
||||||
//createNotificationChannel();
|
//createNotificationChannel();
|
||||||
|
|
|
@ -100,10 +100,10 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
val textChar = event.unicodeChar
|
val textChar = event.unicodeChar
|
||||||
if (textChar == 0) {
|
if (textChar == 0) {
|
||||||
// No text, button input.
|
// No text, button input.
|
||||||
NativeLibrary.SubmitInlineKeyboardInput(keyCode)
|
NativeLibrary.submitInlineKeyboardInput(keyCode)
|
||||||
} else {
|
} else {
|
||||||
// Text submitted.
|
// Text submitted.
|
||||||
NativeLibrary.SubmitInlineKeyboardText(textChar.toChar().toString())
|
NativeLibrary.submitInlineKeyboardText(textChar.toChar().toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,9 +132,6 @@ open class EmulationActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private fun restoreState(savedInstanceState: Bundle) {
|
private fun restoreState(savedInstanceState: Bundle) {
|
||||||
game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!!
|
game = savedInstanceState.parcelable(EXTRA_SELECTED_GAME)!!
|
||||||
|
|
||||||
// If an alert prompt was in progress when state was restored, retry displaying it
|
|
||||||
NativeLibrary.retryDisplayAlertPrompt()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableFullscreenImmersive() {
|
private fun enableFullscreenImmersive() {
|
||||||
|
|
|
@ -93,7 +93,7 @@ class GameAdapter(private val activity: AppCompatActivity, var games: ArrayList<
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decodeGameIcon(uri: String): Bitmap? {
|
private fun decodeGameIcon(uri: String): Bitmap? {
|
||||||
val data = NativeLibrary.GetIcon(uri)
|
val data = NativeLibrary.getIcon(uri)
|
||||||
return BitmapFactory.decodeByteArray(
|
return BitmapFactory.decodeByteArray(
|
||||||
data,
|
data,
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -48,7 +48,7 @@ object SoftwareKeyboard {
|
||||||
}
|
}
|
||||||
|
|
||||||
// No longer visible, submit the result.
|
// No longer visible, submit the result.
|
||||||
NativeLibrary.SubmitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
|
NativeLibrary.submitInlineKeyboardInput(KeyEvent.KEYCODE_ENTER)
|
||||||
}
|
}
|
||||||
}, delayMs.toLong())
|
}, delayMs.toLong())
|
||||||
}
|
}
|
||||||
|
|
|
@ -85,7 +85,7 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView {
|
||||||
presenter.onStop(isFinishing)
|
presenter.onStop(isFinishing)
|
||||||
|
|
||||||
// Update framebuffer layout when closing the settings
|
// Update framebuffer layout when closing the settings
|
||||||
NativeLibrary.NotifyOrientationChange(
|
NativeLibrary.notifyOrientationChange(
|
||||||
EmulationMenuSettings.landscapeScreenLayout,
|
EmulationMenuSettings.landscapeScreenLayout,
|
||||||
windowManager.defaultDisplay.rotation
|
windowManager.defaultDisplay.rotation
|
||||||
)
|
)
|
||||||
|
|
|
@ -63,7 +63,7 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView)
|
||||||
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
|
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
|
||||||
settings.saveSettings(activityView)
|
settings.saveSettings(activityView)
|
||||||
}
|
}
|
||||||
NativeLibrary.ReloadSettings()
|
NativeLibrary.reloadSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSettingChanged() {
|
fun onSettingChanged() {
|
||||||
|
|
|
@ -155,7 +155,7 @@ object SettingsFile {
|
||||||
val sortedKeySet: Set<String> = TreeSet(settings.keys)
|
val sortedKeySet: Set<String> = TreeSet(settings.keys)
|
||||||
for (settingKey in sortedKeySet) {
|
for (settingKey in sortedKeySet) {
|
||||||
val setting = settings[settingKey]
|
val setting = settings[settingKey]
|
||||||
NativeLibrary.SetUserSetting(
|
NativeLibrary.setUserSetting(
|
||||||
gameId, mapSectionNameFromIni(
|
gameId, mapSectionNameFromIni(
|
||||||
section.name
|
section.name
|
||||||
), setting!!.key, setting.valueAsString
|
), setting!!.key, setting.valueAsString
|
||||||
|
|
|
@ -182,7 +182,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
val FRAMETIME = 2
|
val FRAMETIME = 2
|
||||||
val SPEED = 3
|
val SPEED = 3
|
||||||
perfStatsUpdater = {
|
perfStatsUpdater = {
|
||||||
val perfStats = NativeLibrary.GetPerfStats()
|
val perfStats = NativeLibrary.getPerfStats()
|
||||||
if (perfStats[FPS] > 0 && _binding != null) {
|
if (perfStats[FPS] > 0 && _binding != null) {
|
||||||
binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS])
|
binding.showFpsText.text = String.format("FPS: %.1f", perfStats[FPS])
|
||||||
}
|
}
|
||||||
|
@ -333,7 +333,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
if (state != State.STOPPED) {
|
if (state != State.STOPPED) {
|
||||||
Log.debug("[EmulationFragment] Stopping emulation.")
|
Log.debug("[EmulationFragment] Stopping emulation.")
|
||||||
state = State.STOPPED
|
state = State.STOPPED
|
||||||
NativeLibrary.StopEmulation()
|
NativeLibrary.stopEmulation()
|
||||||
} else {
|
} else {
|
||||||
Log.warning("[EmulationFragment] Stop called while already stopped.")
|
Log.warning("[EmulationFragment] Stop called while already stopped.")
|
||||||
}
|
}
|
||||||
|
@ -347,8 +347,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
Log.debug("[EmulationFragment] Pausing emulation.")
|
Log.debug("[EmulationFragment] Pausing emulation.")
|
||||||
|
|
||||||
// Release the surface before pausing, since emulation has to be running for that.
|
// Release the surface before pausing, since emulation has to be running for that.
|
||||||
NativeLibrary.SurfaceDestroyed()
|
NativeLibrary.surfaceDestroyed()
|
||||||
NativeLibrary.PauseEmulation()
|
NativeLibrary.pauseEmulation()
|
||||||
} else {
|
} else {
|
||||||
Log.warning("[EmulationFragment] Pause called while already paused.")
|
Log.warning("[EmulationFragment] Pause called while already paused.")
|
||||||
}
|
}
|
||||||
|
@ -357,7 +357,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
@Synchronized
|
@Synchronized
|
||||||
fun run(isActivityRecreated: Boolean) {
|
fun run(isActivityRecreated: Boolean) {
|
||||||
if (isActivityRecreated) {
|
if (isActivityRecreated) {
|
||||||
if (NativeLibrary.IsRunning()) {
|
if (NativeLibrary.isRunning()) {
|
||||||
state = State.PAUSED
|
state = State.PAUSED
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -390,7 +390,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
Log.debug("[EmulationFragment] Surface destroyed.")
|
Log.debug("[EmulationFragment] Surface destroyed.")
|
||||||
when (state) {
|
when (state) {
|
||||||
State.RUNNING -> {
|
State.RUNNING -> {
|
||||||
NativeLibrary.SurfaceDestroyed()
|
NativeLibrary.surfaceDestroyed()
|
||||||
state = State.PAUSED
|
state = State.PAUSED
|
||||||
}
|
}
|
||||||
State.PAUSED -> Log.warning("[EmulationFragment] Surface cleared while emulation paused.")
|
State.PAUSED -> Log.warning("[EmulationFragment] Surface cleared while emulation paused.")
|
||||||
|
@ -403,17 +403,17 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||||
runWhenSurfaceIsValid = false
|
runWhenSurfaceIsValid = false
|
||||||
when (state) {
|
when (state) {
|
||||||
State.STOPPED -> {
|
State.STOPPED -> {
|
||||||
NativeLibrary.SurfaceChanged(surface)
|
NativeLibrary.surfaceChanged(surface)
|
||||||
val mEmulationThread = Thread({
|
val mEmulationThread = Thread({
|
||||||
Log.debug("[EmulationFragment] Starting emulation thread.")
|
Log.debug("[EmulationFragment] Starting emulation thread.")
|
||||||
NativeLibrary.Run(mGamePath)
|
NativeLibrary.run(mGamePath)
|
||||||
}, "NativeEmulation")
|
}, "NativeEmulation")
|
||||||
mEmulationThread.start()
|
mEmulationThread.start()
|
||||||
}
|
}
|
||||||
State.PAUSED -> {
|
State.PAUSED -> {
|
||||||
Log.debug("[EmulationFragment] Resuming emulation.")
|
Log.debug("[EmulationFragment] Resuming emulation.")
|
||||||
NativeLibrary.SurfaceChanged(surface)
|
NativeLibrary.surfaceChanged(surface)
|
||||||
NativeLibrary.UnPauseEmulation()
|
NativeLibrary.unPauseEmulation()
|
||||||
}
|
}
|
||||||
else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
|
else -> Log.debug("[EmulationFragment] Bug, run called while already running.")
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,7 +142,7 @@ class MainActivity : AppCompatActivity(), MainView {
|
||||||
|
|
||||||
private fun refreshFragment() {
|
private fun refreshFragment() {
|
||||||
if (platformGamesFragment != null) {
|
if (platformGamesFragment != null) {
|
||||||
NativeLibrary.ResetRomMetadata()
|
NativeLibrary.resetRomMetadata()
|
||||||
platformGamesFragment!!.refresh()
|
platformGamesFragment!!.refresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ class MainActivity : AppCompatActivity(), MainView {
|
||||||
|
|
||||||
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
||||||
if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "prod.keys")) {
|
if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "prod.keys")) {
|
||||||
if (NativeLibrary.ReloadKeys()) {
|
if (NativeLibrary.reloadKeys()) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
R.string.install_keys_success,
|
R.string.install_keys_success,
|
||||||
|
@ -225,7 +225,7 @@ class MainActivity : AppCompatActivity(), MainView {
|
||||||
|
|
||||||
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
val dstPath = DirectoryInitialization.userDirectory + "/keys/"
|
||||||
if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "key_retail.bin")) {
|
if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "key_retail.bin")) {
|
||||||
if (NativeLibrary.ReloadKeys()) {
|
if (NativeLibrary.reloadKeys()) {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
this,
|
this,
|
||||||
R.string.install_keys_success,
|
R.string.install_keys_success,
|
||||||
|
|
|
@ -16,7 +16,7 @@ object DirectoryInitialization {
|
||||||
fun start(context: Context) {
|
fun start(context: Context) {
|
||||||
if (!areDirectoriesReady) {
|
if (!areDirectoriesReady) {
|
||||||
initializeInternalStorage(context)
|
initializeInternalStorage(context)
|
||||||
NativeLibrary.InitializeEmulation()
|
NativeLibrary.initializeEmulation()
|
||||||
areDirectoriesReady = true
|
areDirectoriesReady = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ object DirectoryInitialization {
|
||||||
private fun initializeInternalStorage(context: Context) {
|
private fun initializeInternalStorage(context: Context) {
|
||||||
try {
|
try {
|
||||||
userPath = context.getExternalFilesDir(null)!!.canonicalPath
|
userPath = context.getExternalFilesDir(null)!!.canonicalPath
|
||||||
NativeLibrary.SetAppDirectory(userPath)
|
NativeLibrary.setAppDirectory(userPath!!)
|
||||||
} catch (e: IOException) {
|
} catch (e: IOException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ object GameHelper {
|
||||||
val gamesUri = Uri.parse(gamesDir)
|
val gamesUri = Uri.parse(gamesDir)
|
||||||
|
|
||||||
// Ensure keys are loaded so that ROM metadata can be decrypted.
|
// Ensure keys are loaded so that ROM metadata can be decrypted.
|
||||||
NativeLibrary.ReloadKeys()
|
NativeLibrary.reloadKeys()
|
||||||
|
|
||||||
val children = FileUtil.listFiles(context, gamesUri)
|
val children = FileUtil.listFiles(context, gamesUri)
|
||||||
for (file in children) {
|
for (file in children) {
|
||||||
|
@ -44,13 +44,13 @@ object GameHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getGame(filePath: String): Game {
|
private fun getGame(filePath: String): Game {
|
||||||
var name = NativeLibrary.GetTitle(filePath)
|
var name = NativeLibrary.getTitle(filePath)
|
||||||
|
|
||||||
// If the game's title field is empty, use the filename.
|
// If the game's title field is empty, use the filename.
|
||||||
if (name.isEmpty()) {
|
if (name.isEmpty()) {
|
||||||
name = filePath.substring(filePath.lastIndexOf("/") + 1)
|
name = filePath.substring(filePath.lastIndexOf("/") + 1)
|
||||||
}
|
}
|
||||||
var gameId = NativeLibrary.GetGameId(filePath)
|
var gameId = NativeLibrary.getGameId(filePath)
|
||||||
|
|
||||||
// If the game's ID field is empty, use the filename without extension.
|
// If the game's ID field is empty, use the filename without extension.
|
||||||
if (gameId.isEmpty()) {
|
if (gameId.isEmpty()) {
|
||||||
|
@ -62,11 +62,11 @@ object GameHelper {
|
||||||
|
|
||||||
return Game(
|
return Game(
|
||||||
name,
|
name,
|
||||||
NativeLibrary.GetDescription(filePath).replace("\n", " "),
|
NativeLibrary.getDescription(filePath).replace("\n", " "),
|
||||||
NativeLibrary.GetRegions(filePath),
|
NativeLibrary.getRegions(filePath),
|
||||||
filePath,
|
filePath,
|
||||||
gameId,
|
gameId,
|
||||||
NativeLibrary.GetCompany(filePath)
|
NativeLibrary.getCompany(filePath)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,7 +67,7 @@ object GpuDriverHelper {
|
||||||
hookLibPath = context.applicationInfo.nativeLibraryDir + "/"
|
hookLibPath = context.applicationInfo.nativeLibraryDir + "/"
|
||||||
|
|
||||||
// Initialize GPU driver.
|
// Initialize GPU driver.
|
||||||
NativeLibrary.InitializeGpuDriver(
|
NativeLibrary.initializeGpuDriver(
|
||||||
hookLibPath,
|
hookLibPath,
|
||||||
driverInstallationPath,
|
driverInstallationPath,
|
||||||
customDriverLibraryName,
|
customDriverLibraryName,
|
||||||
|
|
|
@ -353,32 +353,32 @@ static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceChanged(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jobject surf) {
|
jobject surf) {
|
||||||
EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
|
EmulationSession::GetInstance().SetNativeWindow(ANativeWindow_fromSurface(env, surf));
|
||||||
EmulationSession::GetInstance().SurfaceChanged();
|
EmulationSession::GetInstance().SurfaceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_surfaceDestroyed(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
|
ANativeWindow_release(EmulationSession::GetInstance().NativeWindow());
|
||||||
EmulationSession::GetInstance().SetNativeWindow(nullptr);
|
EmulationSession::GetInstance().SetNativeWindow(nullptr);
|
||||||
EmulationSession::GetInstance().SurfaceChanged();
|
EmulationSession::GetInstance().SurfaceChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_notifyOrientationChange(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jint layout_option,
|
jint layout_option,
|
||||||
jint rotation) {}
|
jint rotation) {}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetAppDirectory(JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setAppDirectory(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_directory) {
|
jstring j_directory) {
|
||||||
Common::FS::SetAppDirectory(GetJString(env, j_directory));
|
Common::FS::SetAppDirectory(GetJString(env, j_directory));
|
||||||
}
|
}
|
||||||
|
|
||||||
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver(
|
void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeGpuDriver(
|
||||||
JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
|
JNIEnv* env, [[maybe_unused]] jclass clazz, jstring hook_lib_dir, jstring custom_driver_dir,
|
||||||
jstring custom_driver_name, jstring file_redirect_dir) {
|
jstring custom_driver_name, jstring file_redirect_dir) {
|
||||||
EmulationSession::GetInstance().InitializeGpuDriver(
|
EmulationSession::GetInstance().InitializeGpuDriver(
|
||||||
|
@ -386,33 +386,33 @@ void JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeGpuDriver(
|
||||||
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
GetJString(env, custom_driver_name), GetJString(env, file_redirect_dir));
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadKeys(JNIEnv* env,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadKeys(JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
Core::Crypto::KeyManager::Instance().ReloadKeys();
|
||||||
return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
|
return static_cast<jboolean>(Core::Crypto::KeyManager::Instance().AreKeysLoaded());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_unPauseEmulation([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
EmulationSession::GetInstance().UnPauseEmulation();
|
EmulationSession::GetInstance().UnPauseEmulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_pauseEmulation([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
EmulationSession::GetInstance().PauseEmulation();
|
EmulationSession::GetInstance().PauseEmulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_stopEmulation([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
EmulationSession::GetInstance().HaltEmulation();
|
EmulationSession::GetInstance().HaltEmulation();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_ResetRomMetadata([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_resetRomMetadata([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
EmulationSession::GetInstance().ResetRomMetadata();
|
EmulationSession::GetInstance().ResetRomMetadata();
|
||||||
}
|
}
|
||||||
|
|
||||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env,
|
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isRunning([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
|
return static_cast<jboolean>(EmulationSession::GetInstance().IsRunning());
|
||||||
}
|
}
|
||||||
|
@ -492,7 +492,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchReleased([[maybe_unused]] JNIE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env,
|
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getIcon([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
[[maybe_unused]] jstring j_filename) {
|
[[maybe_unused]] jstring j_filename) {
|
||||||
auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
|
auto icon_data = EmulationSession::GetInstance().GetRomIcon(GetJString(env, j_filename));
|
||||||
|
@ -502,43 +502,38 @@ jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetTitle([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getTitle([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
[[maybe_unused]] jstring j_filename) {
|
[[maybe_unused]] jstring j_filename) {
|
||||||
auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
|
auto title = EmulationSession::GetInstance().GetRomTitle(GetJString(env, j_filename));
|
||||||
return env->NewStringUTF(title.c_str());
|
return env->NewStringUTF(title.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetDescription([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getDescription([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_filename) {
|
jstring j_filename) {
|
||||||
return j_filename;
|
return j_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGameId([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getGameId([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_filename) {
|
jstring j_filename) {
|
||||||
return j_filename;
|
return j_filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetRegions([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getRegions([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
[[maybe_unused]] jstring j_filename) {
|
[[maybe_unused]] jstring j_filename) {
|
||||||
return env->NewStringUTF("");
|
return env->NewStringUTF("");
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetCompany([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
[[maybe_unused]] jstring j_filename) {
|
[[maybe_unused]] jstring j_filename) {
|
||||||
return env->NewStringUTF("");
|
return env->NewStringUTF("");
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
|
||||||
[[maybe_unused]] jclass clazz) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation
|
|
||||||
[[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||||
// Create the default config.ini.
|
// Create the default config.ini.
|
||||||
Config{};
|
Config{};
|
||||||
|
@ -546,21 +541,21 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitializeEmulation
|
||||||
EmulationSession::GetInstance().System().Initialize();
|
EmulationSession::GetInstance().System().Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env,
|
jint Java_org_yuzu_yuzu_1emu_NativeLibrary_defaultCPUCore([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2Ljava_lang_String_2Z(
|
||||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, [[maybe_unused]] jstring j_file,
|
||||||
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
|
[[maybe_unused]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
Config{};
|
Config{};
|
||||||
}
|
}
|
||||||
|
|
||||||
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env,
|
jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_game_id, jstring j_section,
|
jstring j_game_id, jstring j_section,
|
||||||
jstring j_key) {
|
jstring j_key) {
|
||||||
|
@ -575,7 +570,7 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JN
|
||||||
return env->NewStringUTF("");
|
return env->NewStringUTF("");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_game_id, jstring j_section,
|
jstring j_game_id, jstring j_section,
|
||||||
jstring j_key, jstring j_value) {
|
jstring j_key, jstring j_value) {
|
||||||
|
@ -590,7 +585,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEn
|
||||||
env->ReleaseStringUTFChars(j_value, value.data());
|
env->ReleaseStringUTFChars(j_value, value.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_game_id) {
|
jstring j_game_id) {
|
||||||
std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
|
std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
|
||||||
|
@ -598,7 +593,7 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv*
|
||||||
env->ReleaseStringUTFChars(j_game_id, game_id.data());
|
env->ReleaseStringUTFChars(j_game_id, game_id.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats([[maybe_unused]] JNIEnv* env,
|
jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPerfStats([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
jdoubleArray j_stats = env->NewDoubleArray(4);
|
jdoubleArray j_stats = env->NewDoubleArray(4);
|
||||||
|
|
||||||
|
@ -615,10 +610,10 @@ jdoubleArray Java_org_yuzu_yuzu_1emu_NativeLibrary_GetPerfStats([[maybe_unused]]
|
||||||
return j_stats;
|
return j_stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_SetSysDirectory(
|
void Java_org_yuzu_yuzu_1emu_utils_DirectoryInitialization_setSysDirectory(
|
||||||
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
|
[[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz,
|
[[maybe_unused]] jclass clazz,
|
||||||
jstring j_path) {
|
jstring j_path) {
|
||||||
const std::string path = GetJString(env, j_path);
|
const std::string path = GetJString(env, j_path);
|
||||||
|
@ -630,19 +625,19 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv* env,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_logDeviceInfo([[maybe_unused]] JNIEnv* env,
|
||||||
[[maybe_unused]] jclass clazz) {
|
[[maybe_unused]] jclass clazz) {
|
||||||
LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
|
LOG_INFO(Frontend, "yuzu Version: {}-{}", Common::g_scm_branch, Common::g_scm_desc);
|
||||||
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
|
LOG_INFO(Frontend, "Host OS: Android API level {}", android_get_device_api_level());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardText(JNIEnv* env, jclass clazz,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardText(JNIEnv* env, jclass clazz,
|
||||||
jstring j_text) {
|
jstring j_text) {
|
||||||
const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
|
const std::u16string input = Common::UTF8ToUTF16(GetJString(env, j_text));
|
||||||
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
|
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardText(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_SubmitInlineKeyboardInput(JNIEnv* env, jclass clazz,
|
void Java_org_yuzu_yuzu_1emu_NativeLibrary_submitInlineKeyboardInput(JNIEnv* env, jclass clazz,
|
||||||
jint j_key_code) {
|
jint j_key_code) {
|
||||||
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
|
EmulationSession::GetInstance().SoftwareKeyboard()->SubmitInlineKeyboardInput(j_key_code);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue