diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java deleted file mode 100644 index 7d4714d758..0000000000 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.java +++ /dev/null @@ -1,601 +0,0 @@ -/* - * Copyright 2013 Dolphin Emulator Project - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -package org.dolphinemu.dolphinemu; - -import android.os.Handler; -import android.os.Looper; -import android.util.DisplayMetrics; -import android.view.Surface; -import android.widget.Toast; - -import androidx.annotation.Keep; -import androidx.core.util.Pair; -import androidx.fragment.app.FragmentManager; - -import org.dolphinemu.dolphinemu.activities.EmulationActivity; -import org.dolphinemu.dolphinemu.dialogs.AlertMessage; -import org.dolphinemu.dolphinemu.utils.CompressCallback; -import org.dolphinemu.dolphinemu.utils.Log; - -import java.lang.ref.WeakReference; -import java.util.concurrent.Semaphore; - -/** - * Class which contains methods that interact - * with the native side of the Dolphin code. - */ -public final class NativeLibrary -{ - private static final Semaphore sAlertMessageSemaphore = new Semaphore(0); - private static boolean sIsShowingAlertMessage = false; - - private static WeakReference sEmulationActivity = new WeakReference<>(null); - - /** - * Returns the current instance of EmulationActivity. - * There should only ever be one EmulationActivity instantiated. - */ - public static EmulationActivity getEmulationActivity() - { - return sEmulationActivity.get(); - } - - /** - * Button type, for legacy use only - */ - public static final class ButtonType - { - public static final int BUTTON_A = 0; - public static final int BUTTON_B = 1; - public static final int BUTTON_START = 2; - public static final int BUTTON_X = 3; - public static final int BUTTON_Y = 4; - public static final int BUTTON_Z = 5; - public static final int BUTTON_UP = 6; - public static final int BUTTON_DOWN = 7; - public static final int BUTTON_LEFT = 8; - public static final int BUTTON_RIGHT = 9; - public static final int STICK_MAIN = 10; - public static final int STICK_MAIN_UP = 11; - public static final int STICK_MAIN_DOWN = 12; - public static final int STICK_MAIN_LEFT = 13; - public static final int STICK_MAIN_RIGHT = 14; - public static final int STICK_C = 15; - public static final int STICK_C_UP = 16; - public static final int STICK_C_DOWN = 17; - public static final int STICK_C_LEFT = 18; - public static final int STICK_C_RIGHT = 19; - public static final int TRIGGER_L = 20; - public static final int TRIGGER_R = 21; - public static final int WIIMOTE_BUTTON_A = 100; - public static final int WIIMOTE_BUTTON_B = 101; - public static final int WIIMOTE_BUTTON_MINUS = 102; - public static final int WIIMOTE_BUTTON_PLUS = 103; - public static final int WIIMOTE_BUTTON_HOME = 104; - public static final int WIIMOTE_BUTTON_1 = 105; - public static final int WIIMOTE_BUTTON_2 = 106; - public static final int WIIMOTE_UP = 107; - public static final int WIIMOTE_DOWN = 108; - public static final int WIIMOTE_LEFT = 109; - public static final int WIIMOTE_RIGHT = 110; - public static final int WIIMOTE_IR = 111; - public static final int WIIMOTE_IR_UP = 112; - public static final int WIIMOTE_IR_DOWN = 113; - public static final int WIIMOTE_IR_LEFT = 114; - public static final int WIIMOTE_IR_RIGHT = 115; - public static final int WIIMOTE_IR_FORWARD = 116; - public static final int WIIMOTE_IR_BACKWARD = 117; - public static final int WIIMOTE_IR_HIDE = 118; - public static final int WIIMOTE_SWING = 119; - public static final int WIIMOTE_SWING_UP = 120; - public static final int WIIMOTE_SWING_DOWN = 121; - public static final int WIIMOTE_SWING_LEFT = 122; - public static final int WIIMOTE_SWING_RIGHT = 123; - public static final int WIIMOTE_SWING_FORWARD = 124; - public static final int WIIMOTE_SWING_BACKWARD = 125; - public static final int WIIMOTE_TILT = 126; - public static final int WIIMOTE_TILT_FORWARD = 127; - public static final int WIIMOTE_TILT_BACKWARD = 128; - public static final int WIIMOTE_TILT_LEFT = 129; - public static final int WIIMOTE_TILT_RIGHT = 130; - public static final int WIIMOTE_TILT_MODIFIER = 131; - public static final int WIIMOTE_SHAKE_X = 132; - public static final int WIIMOTE_SHAKE_Y = 133; - public static final int WIIMOTE_SHAKE_Z = 134; - public static final int NUNCHUK_BUTTON_C = 200; - public static final int NUNCHUK_BUTTON_Z = 201; - public static final int NUNCHUK_STICK = 202; - public static final int NUNCHUK_STICK_UP = 203; - public static final int NUNCHUK_STICK_DOWN = 204; - public static final int NUNCHUK_STICK_LEFT = 205; - public static final int NUNCHUK_STICK_RIGHT = 206; - public static final int NUNCHUK_SWING = 207; - public static final int NUNCHUK_SWING_UP = 208; - public static final int NUNCHUK_SWING_DOWN = 209; - public static final int NUNCHUK_SWING_LEFT = 210; - public static final int NUNCHUK_SWING_RIGHT = 211; - public static final int NUNCHUK_SWING_FORWARD = 212; - public static final int NUNCHUK_SWING_BACKWARD = 213; - public static final int NUNCHUK_TILT = 214; - public static final int NUNCHUK_TILT_FORWARD = 215; - public static final int NUNCHUK_TILT_BACKWARD = 216; - public static final int NUNCHUK_TILT_LEFT = 217; - public static final int NUNCHUK_TILT_RIGHT = 218; - public static final int NUNCHUK_TILT_MODIFIER = 219; - public static final int NUNCHUK_SHAKE_X = 220; - public static final int NUNCHUK_SHAKE_Y = 221; - public static final int NUNCHUK_SHAKE_Z = 222; - public static final int CLASSIC_BUTTON_A = 300; - public static final int CLASSIC_BUTTON_B = 301; - public static final int CLASSIC_BUTTON_X = 302; - public static final int CLASSIC_BUTTON_Y = 303; - public static final int CLASSIC_BUTTON_MINUS = 304; - public static final int CLASSIC_BUTTON_PLUS = 305; - public static final int CLASSIC_BUTTON_HOME = 306; - public static final int CLASSIC_BUTTON_ZL = 307; - public static final int CLASSIC_BUTTON_ZR = 308; - public static final int CLASSIC_DPAD_UP = 309; - public static final int CLASSIC_DPAD_DOWN = 310; - public static final int CLASSIC_DPAD_LEFT = 311; - public static final int CLASSIC_DPAD_RIGHT = 312; - public static final int CLASSIC_STICK_LEFT = 313; - public static final int CLASSIC_STICK_LEFT_UP = 314; - public static final int CLASSIC_STICK_LEFT_DOWN = 315; - public static final int CLASSIC_STICK_LEFT_LEFT = 316; - public static final int CLASSIC_STICK_LEFT_RIGHT = 317; - public static final int CLASSIC_STICK_RIGHT = 318; - public static final int CLASSIC_STICK_RIGHT_UP = 319; - public static final int CLASSIC_STICK_RIGHT_DOWN = 320; - public static final int CLASSIC_STICK_RIGHT_LEFT = 321; - public static final int CLASSIC_STICK_RIGHT_RIGHT = 322; - public static final int CLASSIC_TRIGGER_L = 323; - public static final int CLASSIC_TRIGGER_R = 324; - public static final int GUITAR_BUTTON_MINUS = 400; - public static final int GUITAR_BUTTON_PLUS = 401; - public static final int GUITAR_FRET_GREEN = 402; - public static final int GUITAR_FRET_RED = 403; - public static final int GUITAR_FRET_YELLOW = 404; - public static final int GUITAR_FRET_BLUE = 405; - public static final int GUITAR_FRET_ORANGE = 406; - public static final int GUITAR_STRUM_UP = 407; - public static final int GUITAR_STRUM_DOWN = 408; - public static final int GUITAR_STICK = 409; - public static final int GUITAR_STICK_UP = 410; - public static final int GUITAR_STICK_DOWN = 411; - public static final int GUITAR_STICK_LEFT = 412; - public static final int GUITAR_STICK_RIGHT = 413; - public static final int GUITAR_WHAMMY_BAR = 414; - public static final int DRUMS_BUTTON_MINUS = 500; - public static final int DRUMS_BUTTON_PLUS = 501; - public static final int DRUMS_PAD_RED = 502; - public static final int DRUMS_PAD_YELLOW = 503; - public static final int DRUMS_PAD_BLUE = 504; - public static final int DRUMS_PAD_GREEN = 505; - public static final int DRUMS_PAD_ORANGE = 506; - public static final int DRUMS_PAD_BASS = 507; - public static final int DRUMS_STICK = 508; - public static final int DRUMS_STICK_UP = 509; - public static final int DRUMS_STICK_DOWN = 510; - public static final int DRUMS_STICK_LEFT = 511; - public static final int DRUMS_STICK_RIGHT = 512; - public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600; - public static final int TURNTABLE_BUTTON_RED_LEFT = 601; - public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602; - public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603; - public static final int TURNTABLE_BUTTON_RED_RIGHT = 604; - public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605; - public static final int TURNTABLE_BUTTON_MINUS = 606; - public static final int TURNTABLE_BUTTON_PLUS = 607; - public static final int TURNTABLE_BUTTON_HOME = 608; - public static final int TURNTABLE_BUTTON_EUPHORIA = 609; - public static final int TURNTABLE_TABLE_LEFT = 610; - public static final int TURNTABLE_TABLE_LEFT_LEFT = 611; - public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612; - public static final int TURNTABLE_TABLE_RIGHT = 613; - public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614; - public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615; - public static final int TURNTABLE_STICK = 616; - public static final int TURNTABLE_STICK_UP = 617; - public static final int TURNTABLE_STICK_DOWN = 618; - public static final int TURNTABLE_STICK_LEFT = 619; - public static final int TURNTABLE_STICK_RIGHT = 620; - public static final int TURNTABLE_EFFECT_DIAL = 621; - public static final int TURNTABLE_CROSSFADE = 622; - public static final int TURNTABLE_CROSSFADE_LEFT = 623; - public static final int TURNTABLE_CROSSFADE_RIGHT = 624; - public static final int WIIMOTE_ACCEL_LEFT = 625; - public static final int WIIMOTE_ACCEL_RIGHT = 626; - public static final int WIIMOTE_ACCEL_FORWARD = 627; - public static final int WIIMOTE_ACCEL_BACKWARD = 628; - public static final int WIIMOTE_ACCEL_UP = 629; - public static final int WIIMOTE_ACCEL_DOWN = 630; - public static final int WIIMOTE_GYRO_PITCH_UP = 631; - public static final int WIIMOTE_GYRO_PITCH_DOWN = 632; - public static final int WIIMOTE_GYRO_ROLL_LEFT = 633; - public static final int WIIMOTE_GYRO_ROLL_RIGHT = 634; - public static final int WIIMOTE_GYRO_YAW_LEFT = 635; - public static final int WIIMOTE_GYRO_YAW_RIGHT = 636; - } - - /** - * Button states - */ - public static final class ButtonState - { - public static final int RELEASED = 0; - public static final int PRESSED = 1; - } - - private NativeLibrary() - { - // Disallows instantiation. - } - - /** - * Gets the Dolphin version string. - * - * @return the Dolphin version string. - */ - public static native String GetVersionString(); - - public static native String GetGitRevision(); - - /** - * Saves a screen capture of the game - */ - public static native void SaveScreenShot(); - - /** - * Saves a game state to the slot number. - * - * @param slot The slot location to save state to. - * @param wait If false, returns as early as possible. - * If true, returns once the savestate has been written to disk. - */ - public static native void SaveState(int slot, boolean wait); - - /** - * Saves a game state to the specified path. - * - * @param path The path to save state to. - * @param wait If false, returns as early as possible. - * If true, returns once the savestate has been written to disk. - */ - public static native void SaveStateAs(String path, boolean wait); - - /** - * Loads a game state from the slot number. - * - * @param slot The slot location to load state from. - */ - public static native void LoadState(int slot); - - /** - * Loads a game state from the specified path. - * - * @param path The path to load state from. - */ - public static native void LoadStateAs(String path); - - /** - * Returns when the savestate in the given slot was created, or 0 if the slot is empty. - */ - public static native long GetUnixTimeOfStateSlot(int slot); - - /** - * Sets the current working user directory - * If not set, it auto-detects a location - */ - public static native void SetUserDirectory(String directory); - - /** - * Returns the current working user directory - */ - public static native String GetUserDirectory(); - - public static native void SetCacheDirectory(String directory); - - public static native String GetCacheDirectory(); - - public static native int DefaultCPUCore(); - - public static native String GetDefaultGraphicsBackendConfigName(); - - public static native int GetMaxLogLevel(); - - public static native void ReloadConfig(); - - public static native void ResetDolphinSettings(); - - public static native void UpdateGCAdapterScanThread(); - - /** - * Initializes the native parts of the app. - * - * Should be called at app start before running any other native code - * (other than the native methods in DirectoryInitialization). - */ - public static native void Initialize(); - - /** - * Tells analytics that Dolphin has been started. - * - * Since users typically don't explicitly close Android apps, it's appropriate to - * call this not only when the app starts but also when the user returns to the app - * after not using it for a significant amount of time. - */ - public static native void ReportStartToAnalytics(); - - public static native void GenerateNewStatisticsId(); - - /** - * Begins emulation. - */ - public static native void Run(String[] path, boolean riivolution); - - /** - * Begins emulation from the specified savestate. - */ - public static native void Run(String[] path, boolean riivolution, String savestatePath, - boolean deleteSavestate); - - /** - * Begins emulation of the System Menu. - */ - public static native void RunSystemMenu(); - - public static native void ChangeDisc(String path); - - // Surface Handling - public static native void SurfaceChanged(Surface surf); - - public static native void SurfaceDestroyed(); - - public static native boolean HasSurface(); - - /** - * Unpauses emulation from a paused state. - */ - public static native void UnPauseEmulation(); - - /** - * Pauses emulation. - */ - public static native void PauseEmulation(boolean overrideAchievementRestrictions); - - /** - * Stops emulation. - */ - public static native void StopEmulation(); - - /** - * Ensures that IsRunning will return true from now on until emulation exits. - * (If this is not called, IsRunning will start returning true at some point - * after calling Run.) - */ - public static native void SetIsBooting(); - - /** - * Returns true if emulation is running (or is paused). - */ - public static native boolean IsRunning(); - - /** - * Returns true if emulation is running and not paused. - */ - public static native boolean IsRunningAndUnpaused(); - - /** - * Returns true if emulation is fully shut down. - */ - public static native boolean IsUninitialized(); - - /** - * Re-initialize software JitBlock profiling data - */ - public static native void WipeJitBlockProfilingData(); - - /** - * Writes out the JitBlock Cache log dump - */ - public static native void WriteJitBlockLogDump(); - - /** - * Native EGL functions not exposed by Java bindings - **/ - public static native void eglBindAPI(int api); - - /** - * Provides a way to refresh the connections on Wiimotes - */ - public static native void RefreshWiimotes(); - - public static native Pair[] GetLogTypeNames(); - - public static native void ReloadLoggerConfig(); - - public static native boolean ConvertDiscImage(String inPath, String outPath, int platform, - int format, int blockSize, int compression, int compressionLevel, boolean scrub, - CompressCallback callback); - - public static native String FormatSize(long bytes, int decimals); - - public static native void SetObscuredPixelsLeft(int width); - - public static native void SetObscuredPixelsTop(int height); - - public static native boolean IsGameMetadataValid(); - - public static boolean IsEmulatingWii() - { - CheckGameMetadataValid(); - return IsEmulatingWiiUnchecked(); - } - - public static String GetCurrentGameID() - { - CheckGameMetadataValid(); - return GetCurrentGameIDUnchecked(); - } - - public static String GetCurrentTitleDescription() - { - CheckGameMetadataValid(); - return GetCurrentTitleDescriptionUnchecked(); - } - - private static void CheckGameMetadataValid() - { - if (!IsGameMetadataValid()) - { - throw new IllegalStateException("No game is running"); - } - } - - private static native boolean IsEmulatingWiiUnchecked(); - - private static native String GetCurrentGameIDUnchecked(); - - private static native String GetCurrentTitleDescriptionUnchecked(); - - @Keep - public static void displayToastMsg(final String text, final boolean long_length) - { - final int length = long_length ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT; - new Handler(Looper.getMainLooper()) - .post(() -> Toast.makeText(DolphinApplication.getAppContext(), text, length).show()); - } - - @Keep - public static boolean displayAlertMsg(final String caption, final String text, - final boolean yesNo, final boolean isWarning, final boolean nonBlocking) - { - Log.error("[NativeLibrary] Alert: " + text); - final EmulationActivity emulationActivity = sEmulationActivity.get(); - boolean result = false; - - // We can't use AlertMessages unless we have a non-null activity reference - // and are allowed to block. As a fallback, we can use toasts. - if (emulationActivity == null || nonBlocking) - { - displayToastMsg(text, true); - } - else - { - sIsShowingAlertMessage = true; - - emulationActivity.runOnUiThread(() -> - { - FragmentManager fragmentManager = emulationActivity.getSupportFragmentManager(); - if (fragmentManager.isStateSaved()) - { - // The activity is being destroyed, so we can't use it to display an AlertMessage. - // Fall back to a toast. - Toast.makeText(emulationActivity, text, Toast.LENGTH_LONG).show(); - NotifyAlertMessageLock(); - } - else - { - AlertMessage.Companion.newInstance(caption, text, yesNo, isWarning) - .show(fragmentManager, "AlertMessage"); - } - }); - - // Wait for the lock to notify that it is complete. - try - { - sAlertMessageSemaphore.acquire(); - } - catch (InterruptedException ignored) - { - } - - if (yesNo) - { - result = AlertMessage.Companion.getAlertResult(); - } - } - - sIsShowingAlertMessage = false; - return result; - } - - public static boolean IsShowingAlertMessage() - { - return sIsShowingAlertMessage; - } - - public static void NotifyAlertMessageLock() - { - sAlertMessageSemaphore.release(); - } - - 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(); - } - - @Keep - public static void finishEmulationActivity() - { - final EmulationActivity emulationActivity = sEmulationActivity.get(); - if (emulationActivity == null) - { - Log.warning("[NativeLibrary] EmulationActivity is null."); - } - else - { - Log.verbose("[NativeLibrary] Finishing EmulationActivity."); - emulationActivity.runOnUiThread(emulationActivity::finish); - } - } - - @Keep - public static void updateTouchPointer() - { - final EmulationActivity emulationActivity = sEmulationActivity.get(); - if (emulationActivity == null) - { - Log.warning("[NativeLibrary] EmulationActivity is null."); - } - else - { - emulationActivity.runOnUiThread(emulationActivity::initInputPointer); - } - } - - @Keep - public static void onTitleChanged() - { - final EmulationActivity emulationActivity = sEmulationActivity.get(); - if (emulationActivity == null) - { - Log.warning("[NativeLibrary] EmulationActivity is null."); - } - else - { - emulationActivity.runOnUiThread(emulationActivity::onTitleChanged); - } - } - - @Keep - public static float getRenderSurfaceScale() - { - DisplayMetrics metrics = new DisplayMetrics(); - sEmulationActivity.get().getWindowManager().getDefaultDisplay().getMetrics(metrics); - return metrics.scaledDensity; - } - - public static native float GetGameAspectRatio(); -} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt new file mode 100644 index 0000000000..0b6490b290 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/NativeLibrary.kt @@ -0,0 +1,603 @@ +/* + * Copyright 2013 Dolphin Emulator Project + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +package org.dolphinemu.dolphinemu + +import android.content.res.Resources +import android.view.Surface +import android.widget.Toast +import androidx.annotation.Keep +import androidx.core.content.ContextCompat +import androidx.core.util.Pair +import org.dolphinemu.dolphinemu.activities.EmulationActivity +import org.dolphinemu.dolphinemu.dialogs.AlertMessage +import org.dolphinemu.dolphinemu.utils.CompressCallback +import org.dolphinemu.dolphinemu.utils.Log +import java.lang.ref.WeakReference +import java.util.concurrent.Semaphore + +/** + * Class which contains methods that interact + * with the native side of the Dolphin code. + */ +object NativeLibrary { + /** + * Button type, for legacy use only. + */ + object ButtonType { + const val BUTTON_A = 0 + const val BUTTON_B = 1 + const val BUTTON_START = 2 + const val BUTTON_X = 3 + const val BUTTON_Y = 4 + const val BUTTON_Z = 5 + const val BUTTON_UP = 6 + const val BUTTON_DOWN = 7 + const val BUTTON_LEFT = 8 + const val BUTTON_RIGHT = 9 + const val STICK_MAIN = 10 + const val STICK_MAIN_UP = 11 + const val STICK_MAIN_DOWN = 12 + const val STICK_MAIN_LEFT = 13 + const val STICK_MAIN_RIGHT = 14 + const val STICK_C = 15 + const val STICK_C_UP = 16 + const val STICK_C_DOWN = 17 + const val STICK_C_LEFT = 18 + const val STICK_C_RIGHT = 19 + const val TRIGGER_L = 20 + const val TRIGGER_R = 21 + const val WIIMOTE_BUTTON_A = 100 + const val WIIMOTE_BUTTON_B = 101 + const val WIIMOTE_BUTTON_MINUS = 102 + const val WIIMOTE_BUTTON_PLUS = 103 + const val WIIMOTE_BUTTON_HOME = 104 + const val WIIMOTE_BUTTON_1 = 105 + const val WIIMOTE_BUTTON_2 = 106 + const val WIIMOTE_UP = 107 + const val WIIMOTE_DOWN = 108 + const val WIIMOTE_LEFT = 109 + const val WIIMOTE_RIGHT = 110 + const val WIIMOTE_IR = 111 + const val WIIMOTE_IR_UP = 112 + const val WIIMOTE_IR_DOWN = 113 + const val WIIMOTE_IR_LEFT = 114 + const val WIIMOTE_IR_RIGHT = 115 + const val WIIMOTE_IR_FORWARD = 116 + const val WIIMOTE_IR_BACKWARD = 117 + const val WIIMOTE_IR_HIDE = 118 + const val WIIMOTE_SWING = 119 + const val WIIMOTE_SWING_UP = 120 + const val WIIMOTE_SWING_DOWN = 121 + const val WIIMOTE_SWING_LEFT = 122 + const val WIIMOTE_SWING_RIGHT = 123 + const val WIIMOTE_SWING_FORWARD = 124 + const val WIIMOTE_SWING_BACKWARD = 125 + const val WIIMOTE_TILT = 126 + const val WIIMOTE_TILT_FORWARD = 127 + const val WIIMOTE_TILT_BACKWARD = 128 + const val WIIMOTE_TILT_LEFT = 129 + const val WIIMOTE_TILT_RIGHT = 130 + const val WIIMOTE_TILT_MODIFIER = 131 + const val WIIMOTE_SHAKE_X = 132 + const val WIIMOTE_SHAKE_Y = 133 + const val WIIMOTE_SHAKE_Z = 134 + const val NUNCHUK_BUTTON_C = 200 + const val NUNCHUK_BUTTON_Z = 201 + const val NUNCHUK_STICK = 202 + const val NUNCHUK_STICK_UP = 203 + const val NUNCHUK_STICK_DOWN = 204 + const val NUNCHUK_STICK_LEFT = 205 + const val NUNCHUK_STICK_RIGHT = 206 + const val NUNCHUK_SWING = 207 + const val NUNCHUK_SWING_UP = 208 + const val NUNCHUK_SWING_DOWN = 209 + const val NUNCHUK_SWING_LEFT = 210 + const val NUNCHUK_SWING_RIGHT = 211 + const val NUNCHUK_SWING_FORWARD = 212 + const val NUNCHUK_SWING_BACKWARD = 213 + const val NUNCHUK_TILT = 214 + const val NUNCHUK_TILT_FORWARD = 215 + const val NUNCHUK_TILT_BACKWARD = 216 + const val NUNCHUK_TILT_LEFT = 217 + const val NUNCHUK_TILT_RIGHT = 218 + const val NUNCHUK_TILT_MODIFIER = 219 + const val NUNCHUK_SHAKE_X = 220 + const val NUNCHUK_SHAKE_Y = 221 + const val NUNCHUK_SHAKE_Z = 222 + const val CLASSIC_BUTTON_A = 300 + const val CLASSIC_BUTTON_B = 301 + const val CLASSIC_BUTTON_X = 302 + const val CLASSIC_BUTTON_Y = 303 + const val CLASSIC_BUTTON_MINUS = 304 + const val CLASSIC_BUTTON_PLUS = 305 + const val CLASSIC_BUTTON_HOME = 306 + const val CLASSIC_BUTTON_ZL = 307 + const val CLASSIC_BUTTON_ZR = 308 + const val CLASSIC_DPAD_UP = 309 + const val CLASSIC_DPAD_DOWN = 310 + const val CLASSIC_DPAD_LEFT = 311 + const val CLASSIC_DPAD_RIGHT = 312 + const val CLASSIC_STICK_LEFT = 313 + const val CLASSIC_STICK_LEFT_UP = 314 + const val CLASSIC_STICK_LEFT_DOWN = 315 + const val CLASSIC_STICK_LEFT_LEFT = 316 + const val CLASSIC_STICK_LEFT_RIGHT = 317 + const val CLASSIC_STICK_RIGHT = 318 + const val CLASSIC_STICK_RIGHT_UP = 319 + const val CLASSIC_STICK_RIGHT_DOWN = 320 + const val CLASSIC_STICK_RIGHT_LEFT = 321 + const val CLASSIC_STICK_RIGHT_RIGHT = 322 + const val CLASSIC_TRIGGER_L = 323 + const val CLASSIC_TRIGGER_R = 324 + const val GUITAR_BUTTON_MINUS = 400 + const val GUITAR_BUTTON_PLUS = 401 + const val GUITAR_FRET_GREEN = 402 + const val GUITAR_FRET_RED = 403 + const val GUITAR_FRET_YELLOW = 404 + const val GUITAR_FRET_BLUE = 405 + const val GUITAR_FRET_ORANGE = 406 + const val GUITAR_STRUM_UP = 407 + const val GUITAR_STRUM_DOWN = 408 + const val GUITAR_STICK = 409 + const val GUITAR_STICK_UP = 410 + const val GUITAR_STICK_DOWN = 411 + const val GUITAR_STICK_LEFT = 412 + const val GUITAR_STICK_RIGHT = 413 + const val GUITAR_WHAMMY_BAR = 414 + const val DRUMS_BUTTON_MINUS = 500 + const val DRUMS_BUTTON_PLUS = 501 + const val DRUMS_PAD_RED = 502 + const val DRUMS_PAD_YELLOW = 503 + const val DRUMS_PAD_BLUE = 504 + const val DRUMS_PAD_GREEN = 505 + const val DRUMS_PAD_ORANGE = 506 + const val DRUMS_PAD_BASS = 507 + const val DRUMS_STICK = 508 + const val DRUMS_STICK_UP = 509 + const val DRUMS_STICK_DOWN = 510 + const val DRUMS_STICK_LEFT = 511 + const val DRUMS_STICK_RIGHT = 512 + const val TURNTABLE_BUTTON_GREEN_LEFT = 600 + const val TURNTABLE_BUTTON_RED_LEFT = 601 + const val TURNTABLE_BUTTON_BLUE_LEFT = 602 + const val TURNTABLE_BUTTON_GREEN_RIGHT = 603 + const val TURNTABLE_BUTTON_RED_RIGHT = 604 + const val TURNTABLE_BUTTON_BLUE_RIGHT = 605 + const val TURNTABLE_BUTTON_MINUS = 606 + const val TURNTABLE_BUTTON_PLUS = 607 + const val TURNTABLE_BUTTON_HOME = 608 + const val TURNTABLE_BUTTON_EUPHORIA = 609 + const val TURNTABLE_TABLE_LEFT = 610 + const val TURNTABLE_TABLE_LEFT_LEFT = 611 + const val TURNTABLE_TABLE_LEFT_RIGHT = 612 + const val TURNTABLE_TABLE_RIGHT = 613 + const val TURNTABLE_TABLE_RIGHT_LEFT = 614 + const val TURNTABLE_TABLE_RIGHT_RIGHT = 615 + const val TURNTABLE_STICK = 616 + const val TURNTABLE_STICK_UP = 617 + const val TURNTABLE_STICK_DOWN = 618 + const val TURNTABLE_STICK_LEFT = 619 + const val TURNTABLE_STICK_RIGHT = 620 + const val TURNTABLE_EFFECT_DIAL = 621 + const val TURNTABLE_CROSSFADE = 622 + const val TURNTABLE_CROSSFADE_LEFT = 623 + const val TURNTABLE_CROSSFADE_RIGHT = 624 + const val WIIMOTE_ACCEL_LEFT = 625 + const val WIIMOTE_ACCEL_RIGHT = 626 + const val WIIMOTE_ACCEL_FORWARD = 627 + const val WIIMOTE_ACCEL_BACKWARD = 628 + const val WIIMOTE_ACCEL_UP = 629 + const val WIIMOTE_ACCEL_DOWN = 630 + const val WIIMOTE_GYRO_PITCH_UP = 631 + const val WIIMOTE_GYRO_PITCH_DOWN = 632 + const val WIIMOTE_GYRO_ROLL_LEFT = 633 + const val WIIMOTE_GYRO_ROLL_RIGHT = 634 + const val WIIMOTE_GYRO_YAW_LEFT = 635 + const val WIIMOTE_GYRO_YAW_RIGHT = 636 + } + + object ButtonState { + const val RELEASED = 0 + const val PRESSED = 1 + } + + private val alertMessageSemaphore = Semaphore(0) + + @Volatile + private var isShowingAlertMessage = false + private var emulationActivityRef = WeakReference(null) + + /** + * Returns the current instance of EmulationActivity. + * There should only ever be one EmulationActivity instantiated. + */ + @JvmStatic + fun getEmulationActivity(): EmulationActivity? = emulationActivityRef.get() + + @JvmStatic + external fun GetVersionString(): String + + @JvmStatic + external fun GetGitRevision(): String + + /** + * Saves a screen capture of the game. + */ + @JvmStatic + external fun SaveScreenShot() + + /** + * Saves a game state to the slot number. + * + * @param slot The slot location to save state to. + * @param wait If false, returns as early as possible. If true, returns once the savestate has been written to disk. + */ + @JvmStatic + external fun SaveState(slot: Int, wait: Boolean) + + /** + * Saves a game state to the specified path. + * + * @param path The path to save state to. + * @param wait If false, returns as early as possible. If true, returns once the savestate has been written to disk. + */ + @JvmStatic + external fun SaveStateAs(path: String, wait: Boolean) + + /** + * Loads a game state from the slot number. + * + * @param slot The slot location to load state from. + */ + @JvmStatic + external fun LoadState(slot: Int) + + /** + * Loads a game state from the specified path. + * + * @param path The path to load state from. + */ + @JvmStatic + external fun LoadStateAs(path: String) + + /** + * Returns when the savestate in the given slot was created, or 0 if the slot is empty. + */ + @JvmStatic + external fun GetUnixTimeOfStateSlot(slot: Int): Long + + /** + * Sets the current working user directory. If not set, it auto-detects a location. + */ + @JvmStatic + external fun SetUserDirectory(directory: String) + + /** + * Returns the current working user directory. + */ + @JvmStatic + external fun GetUserDirectory(): String + + @JvmStatic + external fun SetCacheDirectory(directory: String) + + @JvmStatic + external fun GetCacheDirectory(): String + + @JvmStatic + external fun DefaultCPUCore(): Int + + @JvmStatic + external fun GetDefaultGraphicsBackendConfigName(): String + + @JvmStatic + external fun GetMaxLogLevel(): Int + + @JvmStatic + external fun ReloadConfig() + + @JvmStatic + external fun ResetDolphinSettings() + + @JvmStatic + external fun UpdateGCAdapterScanThread() + + /** + * Initializes the native parts of the app. + * + * Should be called at app start before running any other native code + * (other than the native methods in DirectoryInitialization). + */ + @JvmStatic + external fun Initialize() + + /** + * Tells analytics that Dolphin has been started. + * + * Since users typically don't explicitly close Android apps, it's appropriate to + * call this not only when the app starts but also when the user returns to the app + * after not using it for a significant amount of time. + */ + @JvmStatic + external fun ReportStartToAnalytics() + + @JvmStatic + external fun GenerateNewStatisticsId() + + /** + * Begins emulation. + */ + @JvmStatic + external fun Run(path: Array, riivolution: Boolean) + + /** + * Begins emulation from the specified savestate. + */ + @JvmStatic + external fun Run( + path: Array, riivolution: Boolean, savestatePath: String, deleteSavestate: Boolean + ) + + /** + * Begins emulation of the System Menu. + */ + @JvmStatic + external fun RunSystemMenu() + + @JvmStatic + external fun ChangeDisc(path: String) + + @JvmStatic + external fun SurfaceChanged(surf: Surface) + + @JvmStatic + external fun SurfaceDestroyed() + + @JvmStatic + external fun HasSurface(): Boolean + + @JvmStatic + external fun UnPauseEmulation() + + @JvmStatic + external fun PauseEmulation(overrideAchievementRestrictions: Boolean) + + @JvmStatic + external fun StopEmulation() + + /** + * Ensures that IsRunning will return true from now on until emulation exits. + * (If this is not called, IsRunning will start returning true at some point + * after calling Run.) + */ + @JvmStatic + external fun SetIsBooting() + + /** + * Returns true if emulation is running or paused. + */ + @JvmStatic + external fun IsRunning(): Boolean + + /** + * Returns true if emulation is running and not paused. + */ + @JvmStatic + external fun IsRunningAndUnpaused(): Boolean + + /** + * Returns true if emulation is fully shut down. + */ + @JvmStatic + external fun IsUninitialized(): Boolean + + /** + * Re-initializes software JitBlock profiling data. + */ + @JvmStatic + external fun WipeJitBlockProfilingData() + + /** + * Writes out the JitBlock Cache log dump. + */ + @JvmStatic + external fun WriteJitBlockLogDump() + + /** + * Native EGL functions not exposed by Java bindings. + */ + @JvmStatic + external fun eglBindAPI(api: Int) + + /** + * Provides a way to refresh Wiimote connections. + */ + @JvmStatic + external fun RefreshWiimotes() + + @JvmStatic + external fun GetLogTypeNames(): Array> + + @JvmStatic + external fun ReloadLoggerConfig() + + @JvmStatic + external fun ConvertDiscImage( + inPath: String, + outPath: String, + platform: Int, + format: Int, + blockSize: Int, + compression: Int, + compressionLevel: Int, + scrub: Boolean, + callback: CompressCallback + ): Boolean + + @JvmStatic + external fun FormatSize(bytes: Long, decimals: Int): String + + @JvmStatic + external fun SetObscuredPixelsLeft(width: Int) + + @JvmStatic + external fun SetObscuredPixelsTop(height: Int) + + @JvmStatic + external fun IsGameMetadataValid(): Boolean + + @JvmStatic + external fun GetGameAspectRatio(): Float + + @JvmStatic + fun IsEmulatingWii(): Boolean { + checkGameMetadataValid() + return IsEmulatingWiiUnchecked() + } + + @JvmStatic + fun GetCurrentGameID(): String { + checkGameMetadataValid() + return GetCurrentGameIDUnchecked() + } + + @JvmStatic + fun GetCurrentTitleDescription(): String { + checkGameMetadataValid() + return GetCurrentTitleDescriptionUnchecked() + } + + @JvmStatic + @Keep + fun displayToastMsg(text: String, long_length: Boolean) { + val context = DolphinApplication.getAppContext() + val length = if (long_length) Toast.LENGTH_LONG else Toast.LENGTH_SHORT + ContextCompat.getMainExecutor(context).execute { + Toast.makeText(context, text, length).show() + } + } + + @JvmStatic + @Keep + fun displayAlertMsg( + caption: String, text: String, yesNo: Boolean, isWarning: Boolean, nonBlocking: Boolean + ): Boolean { + Log.error("[NativeLibrary] Alert: $text") + val emulationActivity = emulationActivityRef.get() + var result = false + + // We can't use AlertMessages unless we have a non-null activity reference + // and are allowed to block. As a fallback, we can use toasts. + if (emulationActivity == null || nonBlocking) { + displayToastMsg(text, true) + } else { + isShowingAlertMessage = true + + emulationActivity.runOnUiThread { + val fragmentManager = emulationActivity.supportFragmentManager + if (fragmentManager.isStateSaved) { + // The activity is being destroyed, so we can't use it to display an AlertMessage. + // Fall back to a toast. + Toast.makeText(emulationActivity, text, Toast.LENGTH_LONG).show() + NotifyAlertMessageLock() + } else { + AlertMessage.newInstance(caption, text, yesNo, isWarning) + .show(fragmentManager, "AlertMessage") + } + } + + // Wait for the lock to notify that it is complete. + try { + alertMessageSemaphore.acquire() + } catch (ignored: InterruptedException) { + Thread.currentThread().interrupt() + } + + if (yesNo) { + result = AlertMessage.getAlertResult() + } + } + + isShowingAlertMessage = false + return result + } + + @JvmStatic + fun IsShowingAlertMessage(): Boolean = isShowingAlertMessage + + @JvmStatic + fun NotifyAlertMessageLock() { + alertMessageSemaphore.release() + } + + @JvmStatic + fun setEmulationActivity(emulationActivity: EmulationActivity) { + Log.verbose("[NativeLibrary] Registering EmulationActivity.") + emulationActivityRef = WeakReference(emulationActivity) + } + + @JvmStatic + fun clearEmulationActivity() { + Log.verbose("[NativeLibrary] Unregistering EmulationActivity.") + emulationActivityRef.clear() + } + + @JvmStatic + @Keep + fun finishEmulationActivity() { + val emulationActivity = emulationActivityRef.get() + if (emulationActivity == null) { + Log.warning("[NativeLibrary] EmulationActivity is null.") + } else { + Log.verbose("[NativeLibrary] Finishing EmulationActivity.") + emulationActivity.runOnUiThread(emulationActivity::finish) + } + } + + @JvmStatic + @Keep + fun updateTouchPointer() { + val emulationActivity = emulationActivityRef.get() + if (emulationActivity == null) { + Log.warning("[NativeLibrary] EmulationActivity is null.") + } else { + emulationActivity.runOnUiThread(emulationActivity::initInputPointer) + } + } + + @JvmStatic + @Keep + fun onTitleChanged() { + val emulationActivity = emulationActivityRef.get() + if (emulationActivity == null) { + Log.warning("[NativeLibrary] EmulationActivity is null.") + } else { + emulationActivity.runOnUiThread(emulationActivity::onTitleChanged) + } + } + + @JvmStatic + @Keep + fun getRenderSurfaceScale(): Float { + val emulationActivity = emulationActivityRef.get() + if (emulationActivity == null) { + Log.warning("[NativeLibrary] EmulationActivity is null.") + return Resources.getSystem().displayMetrics.scaledDensity + } + + return emulationActivity.resources.displayMetrics.scaledDensity + } + + private fun checkGameMetadataValid() { + check(IsGameMetadataValid()) { "No game is running" } + } + + private external fun IsEmulatingWiiUnchecked(): Boolean + + private external fun GetCurrentGameIDUnchecked(): String + + private external fun GetCurrentTitleDescriptionUnchecked(): String +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/AlertMessage.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/AlertMessage.kt index 3c87b324f6..f79fddcdab 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/AlertMessage.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/AlertMessage.kt @@ -16,6 +16,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.NativeConfig class AlertMessage : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val emulationActivity: EmulationActivity = NativeLibrary.getEmulationActivity() + ?: throw IllegalStateException("EmulationActivity missing while showing alert") val args = requireArguments() val title = args.getString(ARG_TITLE).orEmpty() val message = args.getString(ARG_MESSAGE).orEmpty() diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt index 04db24c03a..3b235d765f 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/EmulationFragment.kt @@ -57,9 +57,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { } override fun onCreateView( - inflater: LayoutInflater, - container: ViewGroup?, - savedInstanceState: Bundle? + inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { _binding = FragmentEmulationBinding.inflate(inflater, container, false) return binding.root @@ -98,8 +96,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { override fun onResume() { super.onResume() - if (NativeLibrary.IsGameMetadataValid()) - inputOverlay?.refreshControls() + if (NativeLibrary.IsGameMetadataValid()) inputOverlay?.refreshControls() AfterDirectoryInitializationRunner().runWithLifecycle(this) { run(emulationActivity!!.isActivityRecreated) @@ -126,8 +123,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { fun toggleInputOverlayVisibility(settings: Settings?) { BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.setBoolean( - settings!!, - !BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.boolean + settings!!, !BooleanSetting.MAIN_SHOW_INPUT_OVERLAY.boolean ) inputOverlay?.refreshControls() @@ -206,16 +202,19 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { if (NativeLibrary.IsUninitialized()) { NativeLibrary.SetIsBooting() val emulationThread = Thread({ - if (loadPreviousTemporaryState) { - Log.debug("[EmulationFragment] Starting emulation thread from previous state.") - NativeLibrary.Run(gamePaths, riivolution, temporaryStateFilePath, true) - } if (launchSystemMenu) { Log.debug("[EmulationFragment] Starting emulation thread for the Wii Menu.") NativeLibrary.RunSystemMenu() } else { + val paths = requireNotNull(gamePaths) { + "Cannot start emulation without any game paths" + } + if (loadPreviousTemporaryState) { + Log.debug("[EmulationFragment] Starting emulation thread from previous state.") + NativeLibrary.Run(paths, riivolution, temporaryStateFilePath, true) + } Log.debug("[EmulationFragment] Starting emulation thread.") - NativeLibrary.Run(gamePaths, riivolution) + NativeLibrary.Run(paths, riivolution) } EmulationActivity.stopIgnoringLaunchRequests() }, "NativeEmulation") @@ -239,9 +238,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback { private const val KEY_SYSTEM_MENU = "systemMenu" fun newInstance( - gamePaths: Array?, - riivolution: Boolean, - systemMenu: Boolean + gamePaths: Array?, riivolution: Boolean, systemMenu: Boolean ): EmulationFragment { val args = Bundle() args.apply {