diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5e3a74c0f..55b113297 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -195,3 +195,8 @@ endif()
 if (ENABLE_WEB_SERVICE)
     add_subdirectory(web_service)
 endif()
+
+if (ANDROID)
+    add_subdirectory(android/app/src/main/jni)
+    target_include_directories(yuzu-android PRIVATE android/app/src/main)
+endif()
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt
new file mode 100644
index 000000000..373c0e8bd
--- /dev/null
+++ b/src/android/app/src/main/jni/CMakeLists.txt
@@ -0,0 +1,15 @@
+add_library(yuzu-android SHARED
+    emu_window/emu_window.cpp
+    emu_window/emu_window.h
+    id_cache.cpp
+    id_cache.h
+    native.cpp
+    native.h
+)
+
+set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR})
+
+target_link_libraries(yuzu-android PRIVATE audio_core common core input_common)
+target_link_libraries(yuzu-android PRIVATE android camera2ndk EGL glad inih jnigraphics log)
+
+set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} yuzu-android)
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.cpp b/src/android/app/src/main/jni/emu_window/emu_window.cpp
new file mode 100644
index 000000000..9062c0ae3
--- /dev/null
+++ b/src/android/app/src/main/jni/emu_window/emu_window.cpp
@@ -0,0 +1,58 @@
+#include <android/native_window_jni.h>
+
+#include "common/logging/log.h"
+#include "input_common/drivers/touch_screen.h"
+#include "input_common/drivers/virtual_gamepad.h"
+#include "input_common/main.h"
+#include "jni/emu_window/emu_window.h"
+
+void EmuWindow_Android::OnSurfaceChanged(ANativeWindow* surface) {
+    render_window = surface;
+}
+
+bool EmuWindow_Android::OnTouchEvent(float x, float y, bool pressed) {
+    if (pressed) {
+        input_subsystem->GetTouchScreen()->TouchPressed(NormalizeX(x), NormalizeY(y), 0);
+        return true;
+    }
+
+    input_subsystem->GetTouchScreen()->ReleaseAllTouch();
+    return true;
+}
+
+void EmuWindow_Android::OnTouchMoved(float x, float y) {
+    input_subsystem->GetTouchScreen()->TouchMoved(NormalizeX(x), NormalizeY(y), 0);
+}
+
+void EmuWindow_Android::OnGamepadEvent(int button_id, bool pressed) {
+    input_subsystem->GetVirtualGamepad()->SetButtonState(0, button_id, pressed);
+}
+
+void EmuWindow_Android::OnGamepadMoveEvent(float x, float y) {
+    input_subsystem->GetVirtualGamepad()->SetStickPosition(
+        0, InputCommon::VirtualGamepad::VirtualStick::Left, x, y);
+}
+
+EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_,
+                                     ANativeWindow* surface_)
+    : input_subsystem{input_subsystem_} {
+    LOG_INFO(Frontend, "initializing");
+
+    if (!surface_) {
+        LOG_CRITICAL(Frontend, "surface is nullptr");
+        return;
+    }
+
+    window_width = ANativeWindow_getWidth(surface_);
+    window_height = ANativeWindow_getHeight(surface_);
+
+    host_window = surface_;
+    window_info.type = Core::Frontend::WindowSystemType::Android;
+    window_info.render_surface = reinterpret_cast<void*>(host_window);
+
+    input_subsystem->Initialize();
+}
+
+EmuWindow_Android::~EmuWindow_Android() {
+    input_subsystem->Shutdown();
+}
diff --git a/src/android/app/src/main/jni/emu_window/emu_window.h b/src/android/app/src/main/jni/emu_window/emu_window.h
new file mode 100644
index 000000000..4af51c517
--- /dev/null
+++ b/src/android/app/src/main/jni/emu_window/emu_window.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "core/frontend/emu_window.h"
+#include "input_common/main.h"
+
+struct ANativeWindow;
+
+class SharedContext_Android : public Core::Frontend::GraphicsContext {
+public:
+    SharedContext_Android() = default;
+    ~SharedContext_Android() = default;
+    void MakeCurrent() override {}
+    void DoneCurrent() override {}
+};
+
+class EmuWindow_Android : public Core::Frontend::EmuWindow {
+public:
+    EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem_, ANativeWindow* surface_);
+    ~EmuWindow_Android();
+
+    void OnSurfaceChanged(ANativeWindow* surface);
+    bool OnTouchEvent(float x, float y, bool pressed);
+    void OnTouchMoved(float x, float y);
+    void OnGamepadEvent(int button, bool pressed);
+    void OnGamepadMoveEvent(float x, float y);
+    void OnFrameDisplayed() override {}
+
+    std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override {
+        return {std::make_unique<SharedContext_Android>()};
+    }
+    bool IsShown() const override {
+        return true;
+    };
+
+private:
+    float NormalizeX(float x) const {
+        return std::clamp(x / window_width, 0.f, 1.f);
+    }
+
+    float NormalizeY(float y) const {
+        return std::clamp(y / window_height, 0.f, 1.f);
+    }
+
+    InputCommon::InputSubsystem* input_subsystem{};
+
+    ANativeWindow* render_window{};
+    ANativeWindow* host_window{};
+
+    float window_width{};
+    float window_height{};
+};
diff --git a/src/android/app/src/main/jni/id_cache.cpp b/src/android/app/src/main/jni/id_cache.cpp
new file mode 100644
index 000000000..2955122be
--- /dev/null
+++ b/src/android/app/src/main/jni/id_cache.cpp
@@ -0,0 +1,36 @@
+#include "jni/id_cache.h"
+
+static JavaVM* s_java_vm;
+static jclass s_native_library_class;
+static jmethodID s_exit_emulation_activity;
+
+namespace IDCache {
+
+JNIEnv* GetEnvForThread() {
+    thread_local static struct OwnedEnv {
+        OwnedEnv() {
+            status = s_java_vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6);
+            if (status == JNI_EDETACHED)
+                s_java_vm->AttachCurrentThread(&env, nullptr);
+        }
+
+        ~OwnedEnv() {
+            if (status == JNI_EDETACHED)
+                s_java_vm->DetachCurrentThread();
+        }
+
+        int status;
+        JNIEnv* env = nullptr;
+    } owned;
+    return owned.env;
+}
+
+jclass GetNativeLibraryClass() {
+    return s_native_library_class;
+}
+
+jmethodID GetExitEmulationActivity() {
+    return s_exit_emulation_activity;
+}
+
+} // namespace IDCache
diff --git a/src/android/app/src/main/jni/id_cache.h b/src/android/app/src/main/jni/id_cache.h
new file mode 100644
index 000000000..2fe07169d
--- /dev/null
+++ b/src/android/app/src/main/jni/id_cache.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <jni.h>
+
+namespace IDCache {
+
+JNIEnv* GetEnvForThread();
+jclass GetNativeLibraryClass();
+jmethodID GetExitEmulationActivity();
+
+} // namespace IDCache
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp
new file mode 100644
index 000000000..b343a1453
--- /dev/null
+++ b/src/android/app/src/main/jni/native.cpp
@@ -0,0 +1,342 @@
+#include <codecvt>
+#include <locale>
+#include <string>
+#include <string_view>
+
+#include <android/api-level.h>
+#include <android/native_window_jni.h>
+
+#include "common/detached_tasks.h"
+#include "common/logging/backend.h"
+#include "common/logging/log.h"
+#include "common/microprofile.h"
+#include "common/scm_rev.h"
+#include "common/scope_exit.h"
+#include "common/settings.h"
+#include "core/core.h"
+#include "core/cpu_manager.h"
+#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/vfs_real.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/perf_stats.h"
+#include "jni/emu_window/emu_window.h"
+#include "jni/id_cache.h"
+#include "video_core/rasterizer_interface.h"
+
+namespace {
+
+ANativeWindow* s_surf{};
+std::unique_ptr<EmuWindow_Android> emu_window;
+std::atomic<bool> stop_run{true};
+Core::System system_;
+
+std::string UTF16ToUTF8(std::u16string_view input) {
+    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+    return convert.to_bytes(input.data(), input.data() + input.size());
+}
+
+std::string GetJString(JNIEnv* env, jstring jstr) {
+    if (!jstr) {
+        return {};
+    }
+
+    const jchar* jchars = env->GetStringChars(jstr, nullptr);
+    const jsize length = env->GetStringLength(jstr);
+    const std::u16string_view string_view(reinterpret_cast<const char16_t*>(jchars), length);
+    const std::string converted_string = UTF16ToUTF8(string_view);
+    env->ReleaseStringChars(jstr, jchars);
+
+    return converted_string;
+}
+
+} // Anonymous namespace
+
+static Core::SystemResultStatus RunEmulation(const std::string& filepath) {
+    Common::Log::Initialize();
+    Common::Log::SetColorConsoleBackendEnabled(true);
+    Common::Log::Start();
+    Common::DetachedTasks detached_tasks;
+
+    MicroProfileOnThreadCreate("EmuThread");
+    SCOPE_EXIT({ MicroProfileShutdown(); });
+
+    LOG_INFO(Frontend, "starting");
+
+    if (filepath.empty()) {
+        LOG_CRITICAL(Frontend, "failed to load: filepath empty!");
+        return Core::SystemResultStatus::ErrorLoader;
+    }
+
+    system_.Initialize();
+    system_.ApplySettings();
+
+    InputCommon::InputSubsystem input_subsystem{};
+
+    emu_window = std::make_unique<EmuWindow_Android>(&input_subsystem, s_surf);
+
+    system_.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
+    system_.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
+    system_.GetFileSystemController().CreateFactories(*system_.GetFilesystem());
+
+    const Core::SystemResultStatus load_result{system_.Load(*emu_window, filepath)};
+
+    if (load_result != Core::SystemResultStatus::Success) {
+        return load_result;
+    }
+
+    system_.GPU().Start();
+    system_.GetCpuManager().OnGpuReady();
+    system_.RegisterExitCallback([&] { exit(0); });
+
+    void(system_.Run());
+
+    if (system_.DebuggerEnabled()) {
+        system_.InitializeDebugger();
+    }
+
+    stop_run = false;
+    while (!stop_run) {
+        std::this_thread::sleep_for(std::chrono::seconds(1));
+    }
+
+    system_.DetachDebugger();
+    void(system_.Pause());
+    system_.ShutdownMainProcess();
+
+    detached_tasks.WaitForAllTasks();
+
+    return Core::SystemResultStatus::Success;
+}
+
+extern "C" {
+
+void Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
+                                                            [[maybe_unused]] jclass clazz,
+                                                            jobject surf) {
+    s_surf = ANativeWindow_fromSurface(env, surf);
+
+    if (emu_window) {
+        emu_window->OnSurfaceChanged(s_surf);
+    }
+
+    LOG_INFO(Frontend, "surface changed");
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
+                                                              [[maybe_unused]] jclass clazz) {
+    ANativeWindow_release(s_surf);
+    s_surf = nullptr;
+    if (emu_window) {
+        emu_window->OnSurfaceChanged(s_surf);
+    }
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_DoFrame(JNIEnv* env, [[maybe_unused]] jclass clazz) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(JNIEnv* env,
+                                                                     [[maybe_unused]] jclass clazz,
+                                                                     jint layout_option,
+                                                                     jint rotation) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(
+    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz,
+    [[maybe_unused]] jstring j_directory) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation([[maybe_unused]] JNIEnv* env,
+                                                              [[maybe_unused]] jclass clazz) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation([[maybe_unused]] JNIEnv* env,
+                                                            [[maybe_unused]] jclass clazz) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_StopEmulation([[maybe_unused]] JNIEnv* env,
+                                                           [[maybe_unused]] jclass clazz) {}
+
+jboolean Java_org_citra_citra_1emu_NativeLibrary_IsRunning([[maybe_unused]] JNIEnv* env,
+                                                           [[maybe_unused]] jclass clazz) {
+    return static_cast<jboolean>(!stop_run);
+}
+
+jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent([[maybe_unused]] JNIEnv* env,
+                                                                [[maybe_unused]] jclass clazz,
+                                                                [[maybe_unused]] jstring j_device,
+                                                                jint j_button, jint action) {
+    emu_window->OnGamepadEvent(j_button, action != 0);
+    return static_cast<jboolean>(true);
+}
+
+jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent([[maybe_unused]] JNIEnv* env,
+                                                                    [[maybe_unused]] jclass clazz,
+                                                                    jstring j_device, jint axis,
+                                                                    jfloat x, jfloat y) {
+    // Clamp joystick movement to supported minimum and maximum.
+    x = std::clamp(x, -1.f, 1.f);
+    y = std::clamp(-y, -1.f, 1.f);
+
+    // Clamp the input to a circle.
+    float r = x * x + y * y;
+    if (r > 1.0f) {
+        r = std::sqrt(r);
+        x /= r;
+        y /= r;
+    }
+    emu_window->OnGamepadMoveEvent(x, y);
+    return static_cast<jboolean>(false);
+}
+
+jboolean Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent([[maybe_unused]] JNIEnv* env,
+                                                                    [[maybe_unused]] jclass clazz,
+                                                                    jstring j_device, jint axis_id,
+                                                                    jfloat axis_val) {
+    return {};
+}
+
+jboolean Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent([[maybe_unused]] JNIEnv* env,
+                                                              [[maybe_unused]] jclass clazz,
+                                                              jfloat x, jfloat y,
+                                                              jboolean pressed) {
+    return static_cast<jboolean>(emu_window->OnTouchEvent(x, y, pressed));
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved([[maybe_unused]] JNIEnv* env,
+                                                          [[maybe_unused]] jclass clazz, jfloat x,
+                                                          jfloat y) {
+    emu_window->OnTouchMoved(x, y);
+}
+
+jintArray Java_org_citra_citra_1emu_NativeLibrary_GetIcon([[maybe_unused]] JNIEnv* env,
+                                                          [[maybe_unused]] jclass clazz,
+                                                          [[maybe_unused]] jstring j_file) {
+    return {};
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetTitle([[maybe_unused]] JNIEnv* env,
+                                                         [[maybe_unused]] jclass clazz,
+                                                         [[maybe_unused]] jstring j_filename) {
+    return env->NewStringUTF("");
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetDescription([[maybe_unused]] JNIEnv* env,
+                                                               [[maybe_unused]] jclass clazz,
+                                                               jstring j_filename) {
+    return j_filename;
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetGameId([[maybe_unused]] JNIEnv* env,
+                                                          [[maybe_unused]] jclass clazz,
+                                                          jstring j_filename) {
+    return j_filename;
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetRegions([[maybe_unused]] JNIEnv* env,
+                                                           [[maybe_unused]] jclass clazz,
+                                                           [[maybe_unused]] jstring j_filename) {
+    return env->NewStringUTF("");
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetCompany([[maybe_unused]] JNIEnv* env,
+                                                           [[maybe_unused]] jclass clazz,
+                                                           [[maybe_unused]] jstring j_filename) {
+    return env->NewStringUTF("");
+}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision([[maybe_unused]] JNIEnv* env,
+                                                               [[maybe_unused]] jclass clazz) {
+    return {};
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile
+    [[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {}
+
+jint Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore([[maybe_unused]] JNIEnv* env,
+                                                            [[maybe_unused]] jclass clazz) {
+    return {};
+}
+
+void Java_org_citra_citra_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]] jstring j_savestate, [[maybe_unused]] jboolean j_delete_savestate) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings([[maybe_unused]] JNIEnv* env,
+                                                            [[maybe_unused]] jclass clazz) {}
+
+jstring Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting([[maybe_unused]] JNIEnv* env,
+                                                               [[maybe_unused]] jclass clazz,
+                                                               jstring j_game_id, jstring j_section,
+                                                               jstring j_key) {
+    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
+    std::string_view section = env->GetStringUTFChars(j_section, 0);
+    std::string_view key = env->GetStringUTFChars(j_key, 0);
+
+    env->ReleaseStringUTFChars(j_game_id, game_id.data());
+    env->ReleaseStringUTFChars(j_section, section.data());
+    env->ReleaseStringUTFChars(j_key, key.data());
+
+    return env->NewStringUTF("");
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting([[maybe_unused]] JNIEnv* env,
+                                                            [[maybe_unused]] jclass clazz,
+                                                            jstring j_game_id, jstring j_section,
+                                                            jstring j_key, jstring j_value) {
+    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
+    std::string_view section = env->GetStringUTFChars(j_section, 0);
+    std::string_view key = env->GetStringUTFChars(j_key, 0);
+    std::string_view value = env->GetStringUTFChars(j_value, 0);
+
+    env->ReleaseStringUTFChars(j_game_id, game_id.data());
+    env->ReleaseStringUTFChars(j_section, section.data());
+    env->ReleaseStringUTFChars(j_key, key.data());
+    env->ReleaseStringUTFChars(j_value, value.data());
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_InitGameIni([[maybe_unused]] JNIEnv* env,
+                                                         [[maybe_unused]] jclass clazz,
+                                                         jstring j_game_id) {
+    std::string_view game_id = env->GetStringUTFChars(j_game_id, 0);
+
+    env->ReleaseStringUTFChars(j_game_id, game_id.data());
+}
+
+jdoubleArray Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats([[maybe_unused]] JNIEnv* env,
+                                                                  [[maybe_unused]] jclass clazz) {
+    jdoubleArray j_stats = env->NewDoubleArray(4);
+
+    if (!stop_run && system_.IsPoweredOn()) {
+        const auto results = system_.GetAndResetPerfStats();
+
+        // Converting the structure into an array makes it easier to pass it to the frontend
+        double stats[4] = {results.system_fps, results.average_game_fps, results.frametime,
+                           results.emulation_speed};
+
+        env->SetDoubleArrayRegion(j_stats, 0, 4, stats);
+    }
+
+    return j_stats;
+}
+
+void Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory(
+    [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jstring j_path) {}
+
+void Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2([[maybe_unused]] JNIEnv* env,
+                                                                      [[maybe_unused]] jclass clazz,
+                                                                      jstring j_path) {
+    const std::string path = GetJString(env, j_path);
+
+    if (!stop_run) {
+        stop_run = true;
+    }
+
+    const Core::SystemResultStatus result{RunEmulation(path)};
+    if (result != Core::SystemResultStatus::Success) {
+        env->CallStaticVoidMethod(IDCache::GetNativeLibraryClass(),
+                                  IDCache::GetExitEmulationActivity(), static_cast<int>(result));
+    }
+}
+
+void Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo([[maybe_unused]] JNIEnv* env,
+                                                           [[maybe_unused]] jclass clazz) {
+    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());
+}
+
+} // extern "C"
diff --git a/src/android/app/src/main/jni/native.h b/src/android/app/src/main/jni/native.h
new file mode 100644
index 000000000..16c90e215
--- /dev/null
+++ b/src/android/app/src/main/jni/native.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <jni.h>
+
+// Function calls from the Java side
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_UnPauseEmulation(JNIEnv* env,
+                                                                                jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_PauseEmulation(JNIEnv* env,
+                                                                              jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_StopEmulation(JNIEnv* env,
+                                                                             jclass clazz);
+
+JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_IsRunning(JNIEnv* env,
+                                                                             jclass clazz);
+
+JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadEvent(
+    JNIEnv* env, jclass clazz, jstring j_device, jint j_button, jint action);
+
+JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadMoveEvent(
+    JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y);
+
+JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onGamePadAxisEvent(
+    JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val);
+
+JNIEXPORT jboolean JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchEvent(JNIEnv* env,
+                                                                                jclass clazz,
+                                                                                jfloat x, jfloat y,
+                                                                                jboolean pressed);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_onTouchMoved(JNIEnv* env,
+                                                                            jclass clazz, jfloat x,
+                                                                            jfloat y);
+
+JNIEXPORT jintArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetIcon(JNIEnv* env,
+                                                                            jclass clazz,
+                                                                            jstring j_file);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetTitle(JNIEnv* env,
+                                                                           jclass clazz,
+                                                                           jstring j_filename);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetDescription(
+    JNIEnv* env, jclass clazz, jstring j_filename);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGameId(JNIEnv* env,
+                                                                            jclass clazz,
+                                                                            jstring j_filename);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetRegions(JNIEnv* env,
+                                                                             jclass clazz,
+                                                                             jstring j_filename);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetCompany(JNIEnv* env,
+                                                                             jclass clazz,
+                                                                             jstring j_filename);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetGitRevision(JNIEnv* env,
+                                                                                 jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserDirectory(
+    JNIEnv* env, jclass clazz, jstring j_directory);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_utils_DirectoryInitialization_SetSysDirectory(
+    JNIEnv* env, jclass clazz, jstring path_);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetSysDirectory(JNIEnv* env,
+                                                                               jclass clazz,
+                                                                               jstring path);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_CreateConfigFile(JNIEnv* env,
+                                                                                jclass clazz);
+
+JNIEXPORT jint JNICALL Java_org_citra_citra_1emu_NativeLibrary_DefaultCPUCore(JNIEnv* env,
+                                                                              jclass clazz);
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetProfiling(JNIEnv* env,
+                                                                            jclass clazz,
+                                                                            jboolean enable);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_WriteProfileResults(JNIEnv* env,
+                                                                                   jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_NotifyOrientationChange(
+    JNIEnv* env, jclass clazz, jint layout_option, jint rotation);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2(
+    JNIEnv* env, jclass clazz, jstring j_path);
+
+JNIEXPORT void JNICALL
+Java_org_citra_citra_1emu_NativeLibrary_Run__Ljava_lang_String_2Ljava_lang_String_2Z(
+    JNIEnv* env, jclass clazz, jstring j_file, jstring j_savestate, jboolean j_delete_savestate);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceChanged(JNIEnv* env,
+                                                                              jclass clazz,
+                                                                              jobject surf);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SurfaceDestroyed(JNIEnv* env,
+                                                                                jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_InitGameIni(JNIEnv* env,
+                                                                           jclass clazz,
+                                                                           jstring j_game_id);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_ReloadSettings(JNIEnv* env,
+                                                                              jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_SetUserSetting(
+    JNIEnv* env, jclass clazz, jstring j_game_id, jstring j_section, jstring j_key,
+    jstring j_value);
+
+JNIEXPORT jstring JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetUserSetting(
+    JNIEnv* env, jclass clazz, jstring game_id, jstring section, jstring key);
+
+JNIEXPORT jdoubleArray JNICALL Java_org_citra_citra_1emu_NativeLibrary_GetPerfStats(JNIEnv* env,
+                                                                                    jclass clazz);
+
+JNIEXPORT void JNICALL Java_org_citra_citra_1emu_NativeLibrary_LogDeviceInfo(JNIEnv* env,
+                                                                             jclass clazz);
+
+#ifdef __cplusplus
+}
+#endif