diff --git a/NativeApp/include/Android/AndroidAppBase.hpp b/NativeApp/include/Android/AndroidAppBase.hpp index 79c5c3e5..000546da 100644 --- a/NativeApp/include/Android/AndroidAppBase.hpp +++ b/NativeApp/include/Android/AndroidAppBase.hpp @@ -26,8 +26,10 @@ #pragma once #include +#include #include +#include "FlagEnum.h" #include "AppBase.hpp" #include "NDKHelper.h" @@ -52,6 +54,31 @@ class AndroidAppBase : public AppBase static int32_t HandleInput(android_app* app, AInputEvent* event); static void HandleCmd(android_app* app, int32_t cmd); + // Android lifecycle status flags. Not app-specific + enum APP_STATUS_FLAGS + { + APP_STATUS_FLAG_NONE = 0x00000000, + + // Set between onCreate and onDestroy + APP_STATUS_FLAG_RUNNING = 0x00000001, + + // Set between onResume and onPause + APP_STATUS_FLAG_ACTIVE = 0x00000002, + + // Set between onWindowFocusChanged(true) and (false) + APP_STATUS_FLAG_FOCUSED = 0x00000004, + + // Set when the app's SurfaceHolder points to a + // valid, nonzero-sized surface + APP_STATUS_FLAG_HAS_REAL_SURFACE = 0x00000008 + }; + + APP_STATUS_FLAGS GetAppStatus(); + void AddAppStatusFlag(APP_STATUS_FLAGS Flag); + void RemoveAppStatusFlag(APP_STATUS_FLAGS Flag); + bool ValueHasAppStatusFlag(APP_STATUS_FLAGS Value, APP_STATUS_FLAGS Flag); + bool HasAppStatusFlag(APP_STATUS_FLAGS Flag); + protected: virtual void Initialize() { @@ -89,11 +116,14 @@ class AndroidAppBase : public AppBase void UpdateFPS(float fFPS); bool initialized_resources_ = false; - bool has_focus_ = false; + + std::atomic app_status_{APP_STATUS_FLAG_NONE}; ASensorManager* sensor_manager_ = nullptr; const ASensor* accelerometer_sensor_ = nullptr; ASensorEventQueue* sensor_event_queue_ = nullptr; }; +DEFINE_FLAG_ENUM_OPERATORS(AndroidAppBase::APP_STATUS_FLAGS) + } // namespace Diligent diff --git a/NativeApp/src/Android/AndroidAppBase.cpp b/NativeApp/src/Android/AndroidAppBase.cpp index 5091b832..107896d0 100644 --- a/NativeApp/src/Android/AndroidAppBase.cpp +++ b/NativeApp/src/Android/AndroidAppBase.cpp @@ -24,6 +24,7 @@ */ #include "AndroidAppBase.hpp" +#include "Errors.hpp" #include "Timer.hpp" #include @@ -118,22 +119,44 @@ void AndroidAppBase::HandleCmd(struct android_app* app, int32_t cmd) AndroidAppBase* eng = (AndroidAppBase*)app->userData; switch (cmd) { - case APP_CMD_SAVE_STATE: - break; - case APP_CMD_INIT_WINDOW: - // The window is being shown, get it ready. - if (app->window != NULL) + LOG_INFO_MESSAGE("APP_CMD_INIT_WINDOW"); + app->window = app->pendingWindow; + if (app->window && + ANativeWindow_getWidth(app->window) && + ANativeWindow_getHeight(app->window)) { + LOG_INFO_MESSAGE("INIT DISPLAY - HAS SURFACE"); eng->InitDisplay(); eng->DrawFrame(); + eng->AddAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); + } + else + { + LOG_INFO_MESSAGE("NO SURFACE"); + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); } break; - case APP_CMD_CONFIG_CHANGED: + case APP_CMD_TERM_WINDOW: + LOG_INFO_MESSAGE("APP_CMD_TERM_WINDOW - LOST SURFACE - TERM DISPLAY"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_HAS_REAL_SURFACE); + } + eng->TermDisplay(); + break; + + // Note that as of NDK r21b (21.1.6352462), APP_CMD_CONTENT_RECT_CHANGED event is never + // generated by android_native_app_glue + case APP_CMD_CONTENT_RECT_CHANGED: { - // This callback is not reliable for handling orientation changes. Depending on the - // device, it may be called before or after the surface has been actually resized. + LOG_INFO_MESSAGE("APP_CMD_CONTENT_RECT_CHANGED"); + + int32_t new_window_width = + app->contentRect.right - app->contentRect.left; + int32_t new_window_height = + app->contentRect.bottom - app->contentRect.top; + eng->WindowResize(new_window_width, new_window_height); break; } @@ -144,45 +167,82 @@ void AndroidAppBase::HandleCmd(struct android_app* app, int32_t cmd) // does not work either - the callback is only called once after the window has been created. case APP_CMD_WINDOW_RESIZED: { - auto new_window_width = ANativeWindow_getWidth(app->window); - auto new_window_height = ANativeWindow_getHeight(app->window); - eng->WindowResize(new_window_width, new_window_height); + LOG_INFO_MESSAGE("APP_CMD_WINDOW_RESIZED"); + if (app->window) + { + int32_t new_window_width = ANativeWindow_getWidth(app->window); + int32_t new_window_height = ANativeWindow_getHeight(app->window); + if (new_window_width && new_window_height) + { + eng->WindowResize(new_window_width, new_window_height); + } + } break; } - // Note that as of NDK r21b (21.1.6352462), APP_CMD_CONTENT_RECT_CHANGED event is never - // generated by android_native_app_glue - case APP_CMD_CONTENT_RECT_CHANGED: - { - auto new_window_width = app->contentRect.right - app->contentRect.left; - auto new_window_height = app->contentRect.bottom - app->contentRect.top; - eng->WindowResize(new_window_width, new_window_height); + case APP_CMD_GAINED_FOCUS: + LOG_INFO_MESSAGE("APP_CMD_GAINED_FOCUS - HAS FOCUS"); + { + eng->AddAppStatusFlag(APP_STATUS_FLAG_FOCUSED); + } + eng->ResumeSensors(); + break; + + case APP_CMD_LOST_FOCUS: + LOG_INFO_MESSAGE("APP_CMD_LOST_FOCUS - LOST FOCUS"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_FOCUSED); + } + eng->SuspendSensors(); + break; + + case APP_CMD_RESUME: + LOG_INFO_MESSAGE("APP_CMD_RESUME - IS ACTIVE"); + { + eng->AddAppStatusFlag(APP_STATUS_FLAG_ACTIVE); + } + break; + + case APP_CMD_START: + LOG_INFO_MESSAGE("APP_CMD_START"); break; - } - case APP_CMD_TERM_WINDOW: case APP_CMD_PAUSE: - // The window is being hidden or closed, clean it up. - eng->TermDisplay(); - eng->has_focus_ = false; + LOG_INFO_MESSAGE("APP_CMD_PAUSE - IS NOT ACTIVE"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_ACTIVE); + } break; case APP_CMD_STOP: + LOG_INFO_MESSAGE("APP_CMD_STOP"); break; - case APP_CMD_GAINED_FOCUS: - eng->ResumeSensors(); - //Start animation - eng->has_focus_ = true; + case APP_CMD_CONFIG_CHANGED: + LOG_INFO_MESSAGE("APP_CMD_CONFIG_CHANGED"); + // AConfiguration_fromAssetManager(app->config, app->activity->assetManager); + // This callback is not reliable for handling orientation changes. Depending on the + // device, it may be called before or after the surface has been actually resized. break; - case APP_CMD_LOST_FOCUS: - eng->SuspendSensors(); - // Also stop animating. - eng->has_focus_ = false; + case APP_CMD_DESTROY: + LOG_INFO_MESSAGE("APP_CMD_DESTROY - IS NOT RUNNING"); + { + eng->RemoveAppStatusFlag(APP_STATUS_FLAG_RUNNING); + } + break; + + case APP_CMD_WINDOW_REDRAW_NEEDED: + LOG_INFO_MESSAGE("APP_CMD_WINDOW_REDRAW_NEEDED"); + if (eng->IsReady()) eng->DrawFrame(); + break; + + case APP_CMD_SAVE_STATE: + LOG_INFO_MESSAGE("APP_CMD_SAVE_STATE"); break; case APP_CMD_LOW_MEMORY: + LOG_INFO_MESSAGE("APP_CMD_LOW_MEMORY"); //Free up GL resources eng->TrimMemory(); break; @@ -244,10 +304,11 @@ void AndroidAppBase::SetState(android_app* state, const char* native_activity_cl bool AndroidAppBase::IsReady() { - if (has_focus_) - return true; - - return false; + APP_STATUS_FLAGS app_status = GetAppStatus(); + return ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_RUNNING) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_ACTIVE) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_FOCUSED) && + ValueHasAppStatusFlag(app_status, APP_STATUS_FLAG_HAS_REAL_SURFACE); } //void Engine::TransformPosition( ndk_helper::Vec2& vec ) @@ -285,4 +346,37 @@ void AndroidAppBase::UpdateFPS(float fFPS) return; } +AndroidAppBase::APP_STATUS_FLAGS AndroidAppBase::GetAppStatus() +{ + return app_status_.load(); +} + +void AndroidAppBase::AddAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + auto LastStoredValue = app_status_.load(); + while (!app_status_.compare_exchange_weak(LastStoredValue, static_cast(LastStoredValue | Flag))) + { + // If exchange fails, LastStoredValue will hold the actual value of app_status_. + } +} + +void AndroidAppBase::RemoveAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + auto LastStoredValue = app_status_.load(); + while (!app_status_.compare_exchange_weak(LastStoredValue, static_cast(LastStoredValue & ~Flag))) + { + // If exchange fails, LastStoredValue will hold the actual value of app_status_. + } +} + +bool AndroidAppBase::ValueHasAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Value, AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + return (Value & Flag) != APP_STATUS_FLAG_NONE; +} + +bool AndroidAppBase::HasAppStatusFlag(AndroidAppBase::APP_STATUS_FLAGS Flag) +{ + return ValueHasAppStatusFlag(app_status_.load(), Flag); +} + } // namespace Diligent diff --git a/NativeApp/src/Android/AndroidMain.cpp b/NativeApp/src/Android/AndroidMain.cpp index 5186c8d2..b7ded455 100644 --- a/NativeApp/src/Android/AndroidMain.cpp +++ b/NativeApp/src/Android/AndroidMain.cpp @@ -42,6 +42,9 @@ using namespace Diligent; void android_main(android_app* state) { std::unique_ptr theApp(CreateApplication()); + + theApp->AddAppStatusFlag(AndroidAppBase::APP_STATUS_FLAG_RUNNING); + theApp->SetState(state, NATIVEACTIVITY_CLASS_NAME); //Init helper functions