#include "GpSystemServices_Android.h" #include "IGpMutex.h" #include "IGpThreadEvent.h" #include "SDL.h" #include #include #include #include struct GpSystemServices_Android_ThreadStartParams { GpSystemServices_Android::ThreadFunc_t m_threadFunc; void *m_threadContext; IGpThreadEvent *m_threadStartEvent; }; static int SDLCALL StaticStartThread(void *lpThreadParameter) { const GpSystemServices_Android_ThreadStartParams *threadParams = static_cast(lpThreadParameter); GpSystemServices_Android::ThreadFunc_t threadFunc = threadParams->m_threadFunc; void *threadContext = threadParams->m_threadContext; IGpThreadEvent *threadStartEvent = threadParams->m_threadStartEvent; threadStartEvent->Signal(); return threadFunc(threadContext); } template class GpMutex_Cpp11 final : public IGpMutex { public: GpMutex_Cpp11(); ~GpMutex_Cpp11(); void Destroy() override; void Lock() override; void Unlock() override; private: TMutex m_mutex; }; template GpMutex_Cpp11::GpMutex_Cpp11() { } template GpMutex_Cpp11::~GpMutex_Cpp11() { } template void GpMutex_Cpp11::Destroy() { this->~GpMutex_Cpp11(); free(this); } template void GpMutex_Cpp11::Lock() { m_mutex.lock(); } template void GpMutex_Cpp11::Unlock() { m_mutex.unlock(); } typedef GpMutex_Cpp11 GpMutex_Cpp11_Vanilla; typedef GpMutex_Cpp11 GpMutex_Cpp11_Recursive; class GpThreadEvent_Cpp11 final : public IGpThreadEvent { public: GpThreadEvent_Cpp11(bool autoReset, bool startSignaled); ~GpThreadEvent_Cpp11(); void Wait() override; bool WaitTimed(uint32_t msec) override; void Signal() override; void Destroy() override; private: std::mutex m_mutex; std::condition_variable m_cvar; bool m_flag; bool m_autoReset; }; GpThreadEvent_Cpp11::GpThreadEvent_Cpp11(bool autoReset, bool startSignaled) : m_flag(startSignaled) , m_autoReset(autoReset) { } GpThreadEvent_Cpp11::~GpThreadEvent_Cpp11() { } void GpThreadEvent_Cpp11::Wait() { std::unique_lock lock(m_mutex); if (m_autoReset) { m_cvar.wait(lock,[&]()->bool{ if (m_flag) { m_flag = false; return true; } else return false; }); } else m_cvar.wait(lock,[&]()->bool{ return m_flag; }); } bool GpThreadEvent_Cpp11::WaitTimed(uint32_t msec) { std::unique_lock lock(m_mutex); if (m_autoReset) { if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{ if (m_flag) { m_flag = false; return true; } else return false; })) return false; } else { if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{ return m_flag; })) return false; } return true; } void GpThreadEvent_Cpp11::Signal() { m_mutex.lock(); m_flag = true; m_mutex.unlock(); if (m_autoReset) m_cvar.notify_one(); else m_cvar.notify_all(); } void GpThreadEvent_Cpp11::Destroy() { this->~GpThreadEvent_Cpp11(); free(this); } GpSystemServices_Android::GpSystemServices_Android() : m_textInputEnabled(false) { } int64_t GpSystemServices_Android::GetTime() const { time_t t = time(nullptr); return static_cast(t) - 2082844800; } void GpSystemServices_Android::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const { time_t t = time(nullptr); tm *tmObject = localtime(&t); year = static_cast(tmObject->tm_year); month = static_cast(tmObject->tm_mon + 1); hour = static_cast(tmObject->tm_hour); minute = static_cast(tmObject->tm_min); second = static_cast(tmObject->tm_sec); } IGpMutex *GpSystemServices_Android::CreateMutex() { GpMutex_Cpp11_Vanilla *mutex = static_cast(malloc(sizeof(GpMutex_Cpp11_Vanilla))); if (!mutex) return nullptr; return new (mutex) GpMutex_Cpp11_Vanilla(); } void *GpSystemServices_Android::CreateThread(ThreadFunc_t threadFunc, void *context) { IGpThreadEvent *evt = CreateThreadEvent(true, false); if (!evt) return nullptr; GpSystemServices_Android_ThreadStartParams startParams; startParams.m_threadContext = context; startParams.m_threadFunc = threadFunc; startParams.m_threadStartEvent = evt; SDL_Thread *thread = SDL_CreateThread(StaticStartThread, "WorkerThread", &startParams); if (thread == nullptr) { evt->Destroy(); return nullptr; } evt->Wait(); evt->Destroy(); return thread; } IGpMutex *GpSystemServices_Android::CreateRecursiveMutex() { GpMutex_Cpp11_Recursive *mutex = static_cast(malloc(sizeof(GpMutex_Cpp11_Recursive))); if (!mutex) return nullptr; return new (mutex) GpMutex_Cpp11_Recursive(); } IGpThreadEvent *GpSystemServices_Android::CreateThreadEvent(bool autoReset, bool startSignaled) { GpThreadEvent_Cpp11 *evt = static_cast(malloc(sizeof(GpThreadEvent_Cpp11))); if (!evt) return nullptr; return new (evt) GpThreadEvent_Cpp11(autoReset, startSignaled); } uint64_t GpSystemServices_Android::GetFreeMemoryCosmetic() const { long pages = sysconf(_SC_AVPHYS_PAGES); long pageSize = sysconf(_SC_PAGE_SIZE); return pages * pageSize; } void GpSystemServices_Android::Beep() const { } bool GpSystemServices_Android::IsTouchscreen() const { return true; } bool GpSystemServices_Android::IsUsingMouseAsTouch() const { return false; } bool GpSystemServices_Android::IsTextInputObstructive() const { return true; } bool GpSystemServices_Android::IsFullscreenPreferred() const { return true; } unsigned int GpSystemServices_Android::GetCPUCount() const { return SDL_GetCPUCount(); } void GpSystemServices_Android::SetTextInputEnabled(bool isEnabled) { m_textInputEnabled = isEnabled; } bool GpSystemServices_Android::IsTextInputEnabled() const { return m_textInputEnabled; } GpSystemServices_Android *GpSystemServices_Android::GetInstance() { return &ms_instance; } GpSystemServices_Android GpSystemServices_Android::ms_instance;