1 /* 2 * Copyright 2013 Dolphin Emulator Project 3 * Licensed under GPLv2+ 4 * Refer to the license.txt file included. 5 */ 6 7 package org.dolphinemu.dolphinemu; 8 9 import android.util.DisplayMetrics; 10 import android.view.Surface; 11 12 import androidx.appcompat.app.AlertDialog; 13 14 import org.dolphinemu.dolphinemu.activities.EmulationActivity; 15 import org.dolphinemu.dolphinemu.utils.CompressCallback; 16 import org.dolphinemu.dolphinemu.utils.Log; 17 import org.dolphinemu.dolphinemu.utils.Rumble; 18 19 import java.lang.ref.WeakReference; 20 import java.util.LinkedHashMap; 21 22 /** 23 * Class which contains methods that interact 24 * with the native side of the Dolphin code. 25 */ 26 public final class NativeLibrary 27 { 28 private static WeakReference<EmulationActivity> sEmulationActivity = new WeakReference<>(null); 29 30 /** 31 * Returns the current instance of EmulationActivity. 32 * There should only ever be one EmulationActivity instantiated. 33 */ getEmulationActivity()34 public static EmulationActivity getEmulationActivity() 35 { 36 return sEmulationActivity.get(); 37 } 38 39 /** 40 * Button type for use in onTouchEvent 41 */ 42 public static final class ButtonType 43 { 44 public static final int BUTTON_A = 0; 45 public static final int BUTTON_B = 1; 46 public static final int BUTTON_START = 2; 47 public static final int BUTTON_X = 3; 48 public static final int BUTTON_Y = 4; 49 public static final int BUTTON_Z = 5; 50 public static final int BUTTON_UP = 6; 51 public static final int BUTTON_DOWN = 7; 52 public static final int BUTTON_LEFT = 8; 53 public static final int BUTTON_RIGHT = 9; 54 public static final int STICK_MAIN = 10; 55 public static final int STICK_MAIN_UP = 11; 56 public static final int STICK_MAIN_DOWN = 12; 57 public static final int STICK_MAIN_LEFT = 13; 58 public static final int STICK_MAIN_RIGHT = 14; 59 public static final int STICK_C = 15; 60 public static final int STICK_C_UP = 16; 61 public static final int STICK_C_DOWN = 17; 62 public static final int STICK_C_LEFT = 18; 63 public static final int STICK_C_RIGHT = 19; 64 public static final int TRIGGER_L = 20; 65 public static final int TRIGGER_R = 21; 66 public static final int WIIMOTE_BUTTON_A = 100; 67 public static final int WIIMOTE_BUTTON_B = 101; 68 public static final int WIIMOTE_BUTTON_MINUS = 102; 69 public static final int WIIMOTE_BUTTON_PLUS = 103; 70 public static final int WIIMOTE_BUTTON_HOME = 104; 71 public static final int WIIMOTE_BUTTON_1 = 105; 72 public static final int WIIMOTE_BUTTON_2 = 106; 73 public static final int WIIMOTE_UP = 107; 74 public static final int WIIMOTE_DOWN = 108; 75 public static final int WIIMOTE_LEFT = 109; 76 public static final int WIIMOTE_RIGHT = 110; 77 public static final int WIIMOTE_IR = 111; 78 public static final int WIIMOTE_IR_UP = 112; 79 public static final int WIIMOTE_IR_DOWN = 113; 80 public static final int WIIMOTE_IR_LEFT = 114; 81 public static final int WIIMOTE_IR_RIGHT = 115; 82 public static final int WIIMOTE_IR_FORWARD = 116; 83 public static final int WIIMOTE_IR_BACKWARD = 117; 84 public static final int WIIMOTE_IR_HIDE = 118; 85 public static final int WIIMOTE_SWING = 119; 86 public static final int WIIMOTE_SWING_UP = 120; 87 public static final int WIIMOTE_SWING_DOWN = 121; 88 public static final int WIIMOTE_SWING_LEFT = 122; 89 public static final int WIIMOTE_SWING_RIGHT = 123; 90 public static final int WIIMOTE_SWING_FORWARD = 124; 91 public static final int WIIMOTE_SWING_BACKWARD = 125; 92 public static final int WIIMOTE_TILT = 126; 93 public static final int WIIMOTE_TILT_FORWARD = 127; 94 public static final int WIIMOTE_TILT_BACKWARD = 128; 95 public static final int WIIMOTE_TILT_LEFT = 129; 96 public static final int WIIMOTE_TILT_RIGHT = 130; 97 public static final int WIIMOTE_TILT_MODIFIER = 131; 98 public static final int WIIMOTE_SHAKE_X = 132; 99 public static final int WIIMOTE_SHAKE_Y = 133; 100 public static final int WIIMOTE_SHAKE_Z = 134; 101 public static final int NUNCHUK_BUTTON_C = 200; 102 public static final int NUNCHUK_BUTTON_Z = 201; 103 public static final int NUNCHUK_STICK = 202; 104 public static final int NUNCHUK_STICK_UP = 203; 105 public static final int NUNCHUK_STICK_DOWN = 204; 106 public static final int NUNCHUK_STICK_LEFT = 205; 107 public static final int NUNCHUK_STICK_RIGHT = 206; 108 public static final int NUNCHUK_SWING = 207; 109 public static final int NUNCHUK_SWING_UP = 208; 110 public static final int NUNCHUK_SWING_DOWN = 209; 111 public static final int NUNCHUK_SWING_LEFT = 210; 112 public static final int NUNCHUK_SWING_RIGHT = 221; 113 public static final int NUNCHUK_SWING_FORWARD = 212; 114 public static final int NUNCHUK_SWING_BACKWARD = 213; 115 public static final int NUNCHUK_TILT = 214; 116 public static final int NUNCHUK_TILT_FORWARD = 215; 117 public static final int NUNCHUK_TILT_BACKWARD = 216; 118 public static final int NUNCHUK_TILT_LEFT = 217; 119 public static final int NUNCHUK_TILT_RIGHT = 218; 120 public static final int NUNCHUK_TILT_MODIFIER = 219; 121 public static final int NUNCHUK_SHAKE_X = 220; 122 public static final int NUNCHUK_SHAKE_Y = 221; 123 public static final int NUNCHUK_SHAKE_Z = 222; 124 public static final int CLASSIC_BUTTON_A = 300; 125 public static final int CLASSIC_BUTTON_B = 301; 126 public static final int CLASSIC_BUTTON_X = 302; 127 public static final int CLASSIC_BUTTON_Y = 303; 128 public static final int CLASSIC_BUTTON_MINUS = 304; 129 public static final int CLASSIC_BUTTON_PLUS = 305; 130 public static final int CLASSIC_BUTTON_HOME = 306; 131 public static final int CLASSIC_BUTTON_ZL = 307; 132 public static final int CLASSIC_BUTTON_ZR = 308; 133 public static final int CLASSIC_DPAD_UP = 309; 134 public static final int CLASSIC_DPAD_DOWN = 310; 135 public static final int CLASSIC_DPAD_LEFT = 311; 136 public static final int CLASSIC_DPAD_RIGHT = 312; 137 public static final int CLASSIC_STICK_LEFT = 313; 138 public static final int CLASSIC_STICK_LEFT_UP = 314; 139 public static final int CLASSIC_STICK_LEFT_DOWN = 315; 140 public static final int CLASSIC_STICK_LEFT_LEFT = 316; 141 public static final int CLASSIC_STICK_LEFT_RIGHT = 317; 142 public static final int CLASSIC_STICK_RIGHT = 318; 143 public static final int CLASSIC_STICK_RIGHT_UP = 319; 144 public static final int CLASSIC_STICK_RIGHT_DOWN = 320; 145 public static final int CLASSIC_STICK_RIGHT_LEFT = 321; 146 public static final int CLASSIC_STICK_RIGHT_RIGHT = 322; 147 public static final int CLASSIC_TRIGGER_L = 323; 148 public static final int CLASSIC_TRIGGER_R = 324; 149 public static final int GUITAR_BUTTON_MINUS = 400; 150 public static final int GUITAR_BUTTON_PLUS = 401; 151 public static final int GUITAR_FRET_GREEN = 402; 152 public static final int GUITAR_FRET_RED = 403; 153 public static final int GUITAR_FRET_YELLOW = 404; 154 public static final int GUITAR_FRET_BLUE = 405; 155 public static final int GUITAR_FRET_ORANGE = 406; 156 public static final int GUITAR_STRUM_UP = 407; 157 public static final int GUITAR_STRUM_DOWN = 408; 158 public static final int GUITAR_STICK = 409; 159 public static final int GUITAR_STICK_UP = 410; 160 public static final int GUITAR_STICK_DOWN = 411; 161 public static final int GUITAR_STICK_LEFT = 412; 162 public static final int GUITAR_STICK_RIGHT = 413; 163 public static final int GUITAR_WHAMMY_BAR = 414; 164 public static final int DRUMS_BUTTON_MINUS = 500; 165 public static final int DRUMS_BUTTON_PLUS = 501; 166 public static final int DRUMS_PAD_RED = 502; 167 public static final int DRUMS_PAD_YELLOW = 503; 168 public static final int DRUMS_PAD_BLUE = 504; 169 public static final int DRUMS_PAD_GREEN = 505; 170 public static final int DRUMS_PAD_ORANGE = 506; 171 public static final int DRUMS_PAD_BASS = 507; 172 public static final int DRUMS_STICK = 508; 173 public static final int DRUMS_STICK_UP = 509; 174 public static final int DRUMS_STICK_DOWN = 510; 175 public static final int DRUMS_STICK_LEFT = 511; 176 public static final int DRUMS_STICK_RIGHT = 512; 177 public static final int TURNTABLE_BUTTON_GREEN_LEFT = 600; 178 public static final int TURNTABLE_BUTTON_RED_LEFT = 601; 179 public static final int TURNTABLE_BUTTON_BLUE_LEFT = 602; 180 public static final int TURNTABLE_BUTTON_GREEN_RIGHT = 603; 181 public static final int TURNTABLE_BUTTON_RED_RIGHT = 604; 182 public static final int TURNTABLE_BUTTON_BLUE_RIGHT = 605; 183 public static final int TURNTABLE_BUTTON_MINUS = 606; 184 public static final int TURNTABLE_BUTTON_PLUS = 607; 185 public static final int TURNTABLE_BUTTON_HOME = 608; 186 public static final int TURNTABLE_BUTTON_EUPHORIA = 609; 187 public static final int TURNTABLE_TABLE_LEFT = 610; 188 public static final int TURNTABLE_TABLE_LEFT_LEFT = 611; 189 public static final int TURNTABLE_TABLE_LEFT_RIGHT = 612; 190 public static final int TURNTABLE_TABLE_RIGHT = 613; 191 public static final int TURNTABLE_TABLE_RIGHT_LEFT = 614; 192 public static final int TURNTABLE_TABLE_RIGHT_RIGHT = 615; 193 public static final int TURNTABLE_STICK = 616; 194 public static final int TURNTABLE_STICK_UP = 617; 195 public static final int TURNTABLE_STICK_DOWN = 618; 196 public static final int TURNTABLE_STICK_LEFT = 619; 197 public static final int TURNTABLE_STICK_RIGHT = 620; 198 public static final int TURNTABLE_EFFECT_DIAL = 621; 199 public static final int TURNTABLE_CROSSFADE = 622; 200 public static final int TURNTABLE_CROSSFADE_LEFT = 623; 201 public static final int TURNTABLE_CROSSFADE_RIGHT = 624; 202 public static final int WIIMOTE_ACCEL_LEFT = 625; 203 public static final int WIIMOTE_ACCEL_RIGHT = 626; 204 public static final int WIIMOTE_ACCEL_FORWARD = 627; 205 public static final int WIIMOTE_ACCEL_BACKWARD = 628; 206 public static final int WIIMOTE_ACCEL_UP = 629; 207 public static final int WIIMOTE_ACCEL_DOWN = 630; 208 public static final int WIIMOTE_GYRO_PITCH_UP = 631; 209 public static final int WIIMOTE_GYRO_PITCH_DOWN = 632; 210 public static final int WIIMOTE_GYRO_ROLL_LEFT = 633; 211 public static final int WIIMOTE_GYRO_ROLL_RIGHT = 634; 212 public static final int WIIMOTE_GYRO_YAW_LEFT = 635; 213 public static final int WIIMOTE_GYRO_YAW_RIGHT = 636; 214 } 215 216 /** 217 * Button states 218 */ 219 public static final class ButtonState 220 { 221 public static final int RELEASED = 0; 222 public static final int PRESSED = 1; 223 } 224 NativeLibrary()225 private NativeLibrary() 226 { 227 // Disallows instantiation. 228 } 229 230 /** 231 * Default touchscreen device 232 */ 233 public static final String TouchScreenDevice = "Touchscreen"; 234 235 /** 236 * Handles button press events for a gamepad. 237 * 238 * @param Device The input descriptor of the gamepad. 239 * @param Button Key code identifying which button was pressed. 240 * @param Action Mask identifying which action is happening (button pressed down, or button released). 241 * @return If we handled the button press. 242 */ onGamePadEvent(String Device, int Button, int Action)243 public static native boolean onGamePadEvent(String Device, int Button, int Action); 244 245 /** 246 * Handles gamepad movement events. 247 * 248 * @param Device The device ID of the gamepad. 249 * @param Axis The axis ID 250 * @param Value The value of the axis represented by the given ID. 251 */ onGamePadMoveEvent(String Device, int Axis, float Value)252 public static native void onGamePadMoveEvent(String Device, int Axis, float Value); 253 254 /** 255 * Rumble sent from native. Currently only supports phone rumble. 256 * 257 * @param padID Ignored for now. Future use would be to pass rumble to a connected controller 258 * @param state Ignored for now since phone rumble can't just be 'turned' on/off 259 */ rumble(int padID, double state)260 public static void rumble(int padID, double state) 261 { 262 final EmulationActivity emulationActivity = sEmulationActivity.get(); 263 if (emulationActivity == null) 264 { 265 Log.warning("[NativeLibrary] EmulationActivity is null"); 266 return; 267 } 268 269 Rumble.checkRumble(padID, state); 270 } 271 SetMotionSensorsEnabled(boolean accelerometerEnabled, boolean gyroscopeEnabled)272 public static native void SetMotionSensorsEnabled(boolean accelerometerEnabled, 273 boolean gyroscopeEnabled); 274 275 // Angle is in radians and should be non-negative GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle)276 public static native double GetInputRadiusAtAngle(int emu_pad_id, int stick, double angle); 277 278 /** 279 * Gets the Dolphin version string. 280 * 281 * @return the Dolphin version string. 282 */ GetVersionString()283 public static native String GetVersionString(); 284 GetGitRevision()285 public static native String GetGitRevision(); 286 287 /** 288 * Saves a screen capture of the game 289 */ SaveScreenShot()290 public static native void SaveScreenShot(); 291 292 /** 293 * Saves a game state to the slot number. 294 * 295 * @param slot The slot location to save state to. 296 * @param wait If false, returns as early as possible. 297 * If true, returns once the savestate has been written to disk. 298 */ SaveState(int slot, boolean wait)299 public static native void SaveState(int slot, boolean wait); 300 301 /** 302 * Saves a game state to the specified path. 303 * 304 * @param path The path to save state to. 305 * @param wait If false, returns as early as possible. 306 * If true, returns once the savestate has been written to disk. 307 */ SaveStateAs(String path, boolean wait)308 public static native void SaveStateAs(String path, boolean wait); 309 310 /** 311 * Loads a game state from the slot number. 312 * 313 * @param slot The slot location to load state from. 314 */ LoadState(int slot)315 public static native void LoadState(int slot); 316 317 /** 318 * Loads a game state from the specified path. 319 * 320 * @param path The path to load state from. 321 */ LoadStateAs(String path)322 public static native void LoadStateAs(String path); 323 324 /** 325 * Sets the current working user directory 326 * If not set, it auto-detects a location 327 */ SetUserDirectory(String directory)328 public static native void SetUserDirectory(String directory); 329 330 /** 331 * Returns the current working user directory 332 */ GetUserDirectory()333 public static native String GetUserDirectory(); 334 SetCacheDirectory(String directory)335 public static native void SetCacheDirectory(String directory); 336 DefaultCPUCore()337 public static native int DefaultCPUCore(); 338 GetDefaultGraphicsBackendName()339 public static native String GetDefaultGraphicsBackendName(); 340 GetMaxLogLevel()341 public static native int GetMaxLogLevel(); 342 ReloadConfig()343 public static native void ReloadConfig(); 344 UpdateGCAdapterScanThread()345 public static native void UpdateGCAdapterScanThread(); 346 347 /** 348 * Initializes the native parts of the app. 349 * 350 * Should be called at app start before running any other native code 351 * (other than the native methods in DirectoryInitialization). 352 */ Initialize()353 public static native void Initialize(); 354 355 /** 356 * Tells analytics that Dolphin has been started. 357 * 358 * Since users typically don't explicitly close Android apps, it's appropriate to 359 * call this not only when the app starts but also when the user returns to the app 360 * after not using it for a significant amount of time. 361 */ ReportStartToAnalytics()362 public static native void ReportStartToAnalytics(); 363 364 /** 365 * Begins emulation. 366 */ Run(String[] path)367 public static native void Run(String[] path); 368 369 /** 370 * Begins emulation from the specified savestate. 371 */ Run(String[] path, String savestatePath, boolean deleteSavestate)372 public static native void Run(String[] path, String savestatePath, boolean deleteSavestate); 373 ChangeDisc(String path)374 public static native void ChangeDisc(String path); 375 376 // Surface Handling SurfaceChanged(Surface surf)377 public static native void SurfaceChanged(Surface surf); 378 SurfaceDestroyed()379 public static native void SurfaceDestroyed(); 380 381 /** 382 * Unpauses emulation from a paused state. 383 */ UnPauseEmulation()384 public static native void UnPauseEmulation(); 385 386 /** 387 * Pauses emulation. 388 */ PauseEmulation()389 public static native void PauseEmulation(); 390 391 /** 392 * Stops emulation. 393 */ StopEmulation()394 public static native void StopEmulation(); 395 WaitUntilDoneBooting()396 public static native void WaitUntilDoneBooting(); 397 398 /** 399 * Returns true if emulation is running (or is paused). 400 */ IsRunning()401 public static native boolean IsRunning(); 402 403 /** 404 * Enables or disables CPU block profiling 405 * 406 * @param enable 407 */ SetProfiling(boolean enable)408 public static native void SetProfiling(boolean enable); 409 410 /** 411 * Writes out the block profile results 412 */ WriteProfileResults()413 public static native void WriteProfileResults(); 414 415 /** 416 * Native EGL functions not exposed by Java bindings 417 **/ eglBindAPI(int api)418 public static native void eglBindAPI(int api); 419 420 /** 421 * Provides a way to refresh the connections on Wiimotes 422 */ RefreshWiimotes()423 public static native void RefreshWiimotes(); 424 ReloadWiimoteConfig()425 public static native void ReloadWiimoteConfig(); 426 GetLogTypeNames()427 public static native LinkedHashMap<String, String> GetLogTypeNames(); 428 ReloadLoggerConfig()429 public static native void ReloadLoggerConfig(); 430 InstallWAD(String file)431 public static native boolean InstallWAD(String file); 432 ConvertDiscImage(String inPath, String outPath, int platform, int format, int blockSize, int compression, int compressionLevel, boolean scrub, CompressCallback callback)433 public static native boolean ConvertDiscImage(String inPath, String outPath, int platform, 434 int format, int blockSize, int compression, int compressionLevel, boolean scrub, 435 CompressCallback callback); 436 FormatSize(long bytes, int decimals)437 public static native String FormatSize(long bytes, int decimals); 438 SetObscuredPixelsLeft(int width)439 public static native void SetObscuredPixelsLeft(int width); 440 SetObscuredPixelsTop(int height)441 public static native void SetObscuredPixelsTop(int height); 442 443 private static boolean alertResult = false; 444 displayAlertMsg(final String caption, final String text, final boolean yesNo)445 public static boolean displayAlertMsg(final String caption, final String text, 446 final boolean yesNo) 447 { 448 Log.error("[NativeLibrary] Alert: " + text); 449 final EmulationActivity emulationActivity = sEmulationActivity.get(); 450 boolean result = false; 451 if (emulationActivity == null) 452 { 453 Log.warning("[NativeLibrary] EmulationActivity is null, can't do panic alert."); 454 } 455 else 456 { 457 // Create object used for waiting. 458 final Object lock = new Object(); 459 AlertDialog.Builder builder = new AlertDialog.Builder(emulationActivity, 460 R.style.DolphinDialogBase) 461 .setTitle(caption) 462 .setMessage(text); 463 464 // If not yes/no dialog just have one button that dismisses modal, 465 // otherwise have a yes and no button that sets alertResult accordingly. 466 if (!yesNo) 467 { 468 builder 469 .setCancelable(false) 470 .setPositiveButton("OK", (dialog, whichButton) -> 471 { 472 dialog.dismiss(); 473 synchronized (lock) 474 { 475 lock.notify(); 476 } 477 }); 478 } 479 else 480 { 481 alertResult = false; 482 483 builder 484 .setPositiveButton("Yes", (dialog, whichButton) -> 485 { 486 alertResult = true; 487 dialog.dismiss(); 488 synchronized (lock) 489 { 490 lock.notify(); 491 } 492 }) 493 .setNegativeButton("No", (dialog, whichButton) -> 494 { 495 alertResult = false; 496 dialog.dismiss(); 497 synchronized (lock) 498 { 499 lock.notify(); 500 } 501 }); 502 } 503 504 // Show the AlertDialog on the main thread. 505 emulationActivity.runOnUiThread(builder::show); 506 507 // Wait for the lock to notify that it is complete. 508 synchronized (lock) 509 { 510 try 511 { 512 lock.wait(); 513 } 514 catch (Exception ignored) 515 { 516 } 517 } 518 519 if (yesNo) 520 result = alertResult; 521 } 522 return result; 523 } 524 setEmulationActivity(EmulationActivity emulationActivity)525 public static void setEmulationActivity(EmulationActivity emulationActivity) 526 { 527 Log.verbose("[NativeLibrary] Registering EmulationActivity."); 528 sEmulationActivity = new WeakReference<>(emulationActivity); 529 } 530 clearEmulationActivity()531 public static void clearEmulationActivity() 532 { 533 Log.verbose("[NativeLibrary] Unregistering EmulationActivity."); 534 535 sEmulationActivity.clear(); 536 } 537 updateTouchPointer()538 public static void updateTouchPointer() 539 { 540 final EmulationActivity emulationActivity = sEmulationActivity.get(); 541 if (emulationActivity == null) 542 { 543 Log.warning("[NativeLibrary] EmulationActivity is null."); 544 } 545 else 546 { 547 emulationActivity.runOnUiThread(emulationActivity::initInputPointer); 548 } 549 } 550 getRenderSurfaceScale()551 public static float getRenderSurfaceScale() 552 { 553 DisplayMetrics metrics = new DisplayMetrics(); 554 sEmulationActivity.get().getWindowManager().getDefaultDisplay().getMetrics(metrics); 555 return metrics.scaledDensity; 556 } 557 GetGameAspectRatio()558 public static native float GetGameAspectRatio(); 559 } 560