#pragma once #include "android_settings_interface.h" #include "common/byte_stream.h" #include "common/event.h" #include "common/progress_callback.h" #include "core/host_display.h" #include "frontend-common/common_host_interface.h" #include #include #include #include #include #include #include #include struct ANativeWindow; class Controller; class AndroidHostInterface final : public CommonHostInterface { public: AndroidHostInterface(jobject java_object, jobject context_object, std::string user_directory); ~AndroidHostInterface() override; ALWAYS_INLINE ANativeWindow* GetSurface() const { return m_surface; } bool Initialize() override; void Shutdown() override; const char* GetFrontendName() const override; void RequestExit() override; void RunLater(std::function func) override; void ReportError(const char* message) override; void ReportMessage(const char* message) override; std::unique_ptr OpenPackageFile(const char* path, u32 flags) override; bool GetMainDisplayRefreshRate(float* refresh_rate) override; bool IsEmulationThreadRunning() const { return m_emulation_thread_running.load(); } bool IsEmulationThreadPaused() const; bool IsOnEmulationThread() const; void RunOnEmulationThread(std::function function, bool blocking = false); void PauseEmulationThread(bool paused); void StopEmulationThreadLoop(); void EmulationThreadEntryPoint(JNIEnv* env, jobject emulation_activity, SystemBootParameters boot_params, bool resume_state); void SurfaceChanged(ANativeWindow* surface, int format, int width, int height); void SetDisplayAlignment(HostDisplay::Alignment alignment); void SetControllerType(u32 index, std::string_view type_name); void SetControllerButtonState(u32 index, s32 button_code, bool pressed); void SetControllerAxisState(u32 index, s32 button_code, float value); void HandleControllerButtonEvent(u32 controller_index, u32 button_index, bool pressed); void HandleControllerAxisEvent(u32 controller_index, u32 axis_index, float value); void SetFastForwardEnabled(bool enabled); void RefreshGameList(bool invalidate_cache, bool invalidate_database, ProgressCallback* progress_callback); bool ImportPatchCodesFromString(const std::string& str); jobjectArray GetInputProfileNames(JNIEnv* env) const; protected: void SetUserDirectory() override; void RegisterHotkeys() override; bool AcquireHostDisplay() override; void ReleaseHostDisplay() override; std::unique_ptr CreateAudioStream(AudioBackend backend) override; void UpdateControllerInterface() override; void OnSystemPaused(bool paused) override; void OnSystemDestroyed() override; void OnRunningGameChanged(const std::string& path, CDImage* image, const std::string& game_code, const std::string& game_title) override; private: void EmulationThreadLoop(JNIEnv* env); void LoadSettings(SettingsInterface& si) override; void SetVibration(bool enabled); void UpdateVibration(); jobject m_java_object = {}; jobject m_emulation_activity_object = {}; ANativeWindow* m_surface = nullptr; std::mutex m_mutex; std::condition_variable m_sleep_cv; std::deque> m_callback_queue; std::atomic_bool m_callbacks_outstanding{false}; std::atomic_bool m_emulation_thread_stop_request{false}; std::atomic_bool m_emulation_thread_running{false}; std::thread::id m_emulation_thread_id{}; HostDisplay::Alignment m_display_alignment = HostDisplay::Alignment::Center; u64 m_last_vibration_update_time = 0; bool m_last_vibration_state = false; bool m_vibration_enabled = false; }; namespace AndroidHelpers { JNIEnv* GetJNIEnv(); AndroidHostInterface* GetNativeClass(JNIEnv* env, jobject obj); std::string JStringToString(JNIEnv* env, jstring str); std::unique_ptr ReadInputStreamToMemory(JNIEnv* env, jobject obj, u32 chunk_size = 65536); jclass GetStringClass(); } // namespace AndroidHelpers template class LocalRefHolder { public: LocalRefHolder() : m_env(nullptr), m_object(nullptr) {} LocalRefHolder(JNIEnv* env, T object) : m_env(env), m_object(object) {} LocalRefHolder(const LocalRefHolder&) = delete; LocalRefHolder(LocalRefHolder&& move) : m_env(move.m_env), m_object(move.m_object) { move.m_env = nullptr; move.m_object = {}; } ~LocalRefHolder() { if (m_object) m_env->DeleteLocalRef(m_object); } operator T() const { return m_object; } T operator*() const { return m_object; } LocalRefHolder& operator=(const LocalRefHolder&) = delete; LocalRefHolder& operator=(LocalRefHolder&& move) { if (m_object) m_env->DeleteLocalRef(m_object); m_env = move.m_env; m_object = move.m_object; move.m_env = nullptr; move.m_object = {}; return *this; } T Get() const { return m_object; } private: JNIEnv* m_env; T m_object; };