Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixes edge cases in Android Native App rendering #32

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion NativeApp/include/Android/AndroidAppBase.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
#pragma once

#include <memory>
#include <atomic>

#include <android_native_app_glue.h>
#include "FlagEnum.h"
#include "AppBase.hpp"

#include "NDKHelper.h"
Expand All @@ -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()
{
Expand Down Expand Up @@ -89,11 +116,14 @@ class AndroidAppBase : public AppBase
void UpdateFPS(float fFPS);

bool initialized_resources_ = false;
bool has_focus_ = false;

std::atomic<APP_STATUS_FLAGS> 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
164 changes: 129 additions & 35 deletions NativeApp/src/Android/AndroidAppBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

#include "AndroidAppBase.hpp"
#include "Errors.hpp"
#include "Timer.hpp"

#include <android/sensor.h>
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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 )
Expand Down Expand Up @@ -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<APP_STATUS_FLAGS>(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<APP_STATUS_FLAGS>(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
3 changes: 3 additions & 0 deletions NativeApp/src/Android/AndroidMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ using namespace Diligent;
void android_main(android_app* state)
{
std::unique_ptr<AndroidAppBase> theApp(CreateApplication());

theApp->AddAppStatusFlag(AndroidAppBase::APP_STATUS_FLAG_RUNNING);

theApp->SetState(state, NATIVEACTIVITY_CLASS_NAME);

//Init helper functions
Expand Down