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

Move sensor handling to a callback. #1004

Merged
merged 3 commits into from
May 1, 2024
Merged
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
2 changes: 1 addition & 1 deletion native-activity/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {

defaultConfig {
applicationId = 'com.example.native_activity'
minSdkVersion 14
minSdkVersion 21
targetSdkVersion 34
externalNativeBuild {
cmake {
Expand Down
128 changes: 64 additions & 64 deletions native-activity/app/src/main/cpp/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <GLES/gl.h>
#include <android/log.h>
#include <android/sensor.h>
#include <android/set_abort_message.h>
#include <android_native_app_glue.h>
#include <jni.h>

Expand All @@ -30,10 +31,38 @@
#include <initializer_list>
#include <memory>

#define LOGI(...) \
((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) \
((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
#define LOG_TAG "native-activity"

#define _LOG(priority, fmt, ...) \
((void)__android_log_print((priority), (LOG_TAG), (fmt)__VA_OPT__(, ) __VA_ARGS__))

#define LOGE(fmt, ...) _LOG(ANDROID_LOG_ERROR, (fmt)__VA_OPT__(, ) __VA_ARGS__)
#define LOGW(fmt, ...) _LOG(ANDROID_LOG_WARN, (fmt)__VA_OPT__(, ) __VA_ARGS__)
#define LOGI(fmt, ...) _LOG(ANDROID_LOG_INFO, (fmt)__VA_OPT__(, ) __VA_ARGS__)

[[noreturn]] __attribute__((__format__(__printf__, 1, 2))) static void fatal(
const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
char* buf;
if (vasprintf(&buf, fmt, ap) < 0) {
android_set_abort_message("failed for format error message");
DanAlbert marked this conversation as resolved.
Show resolved Hide resolved
} else {
android_set_abort_message(buf);
// Also log directly, since the default Android Studio logcat filter hides
// the backtrace which would otherwise show the abort message.
LOGE("%s", buf);
}
std::abort();
}

#define CHECK_NOT_NULL(value) \
do { \
if ((value) == nullptr) { \
fatal("%s:%d:%s must not be null", __PRETTY_FUNCTION__, __LINE__, \
#value); \
} \
} while (false)

/**
* Our saved state data.
Expand Down Expand Up @@ -61,6 +90,20 @@ struct engine {
int32_t width;
int32_t height;
struct saved_state state;

void CreateSensorListener(ALooper_callbackFunc callback) {
CHECK_NOT_NULL(app);

sensorManager = ASensorManager_getInstance();
if (sensorManager == nullptr) {
return;
}

accelerometerSensor = ASensorManager_getDefaultSensor(
sensorManager, ASENSOR_TYPE_ACCELEROMETER);
sensorEventQueue = ASensorManager_createEventQueue(
sensorManager, app->looper, ALOOPER_POLL_CALLBACK, callback, this);
}
};

/**
Expand Down Expand Up @@ -266,48 +309,22 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
}
}

/*
* AcquireASensorManagerInstance(void)
* Workaround ASensorManager_getInstance() deprecation false alarm
* for Android-N and before, when compiling with NDK-r15
*/
#include <dlfcn.h>
ASensorManager* AcquireASensorManagerInstance(android_app* app) {
if (!app) return nullptr;

typedef ASensorManager* (*PF_GETINSTANCEFORPACKAGE)(const char* name);
void* androidHandle = dlopen("libandroid.so", RTLD_NOW);
auto getInstanceForPackageFunc = (PF_GETINSTANCEFORPACKAGE)dlsym(
androidHandle, "ASensorManager_getInstanceForPackage");
if (getInstanceForPackageFunc) {
JNIEnv* env = nullptr;
app->activity->vm->AttachCurrentThread(&env, nullptr);

jclass android_content_Context = env->GetObjectClass(app->activity->clazz);
jmethodID midGetPackageName = env->GetMethodID(
android_content_Context, "getPackageName", "()Ljava/lang/String;");
auto packageName =
(jstring)env->CallObjectMethod(app->activity->clazz, midGetPackageName);

const char* nativePackageName =
env->GetStringUTFChars(packageName, nullptr);
ASensorManager* mgr = getInstanceForPackageFunc(nativePackageName);
env->ReleaseStringUTFChars(packageName, nativePackageName);
app->activity->vm->DetachCurrentThread();
if (mgr) {
dlclose(androidHandle);
return mgr;
}
}
int OnSensorEvent(int /* fd */, int /* events */, void* data) {
CHECK_NOT_NULL(data);
engine* engine = reinterpret_cast<struct engine*>(data);

typedef ASensorManager* (*PF_GETINSTANCE)();
auto getInstanceFunc =
(PF_GETINSTANCE)dlsym(androidHandle, "ASensorManager_getInstance");
// by all means at this point, ASensorManager_getInstance should be available
assert(getInstanceFunc);
dlclose(androidHandle);
CHECK_NOT_NULL(engine->accelerometerSensor);
ASensorEvent event;
while (ASensorEventQueue_getEvents(engine->sensorEventQueue, &event, 1) > 0) {
LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x,
event.acceleration.y, event.acceleration.z);
}

return getInstanceFunc();
// From the docs:
//
// Implementations should return 1 to continue receiving callbacks, or 0 to
// have this file descriptor and callback unregistered from the looper.
return 1;
}

/**
Expand All @@ -325,11 +342,7 @@ void android_main(struct android_app* state) {
engine.app = state;

// Prepare to monitor accelerometer
engine.sensorManager = AcquireASensorManagerInstance(state);
engine.accelerometerSensor = ASensorManager_getDefaultSensor(
engine.sensorManager, ASENSOR_TYPE_ACCELEROMETER);
engine.sensorEventQueue = ASensorManager_createEventQueue(
engine.sensorManager, state->looper, LOOPER_ID_USER, nullptr, nullptr);
engine.CreateSensorListener(OnSensorEvent);

if (state->savedState != nullptr) {
// We are starting with a previous saved state; restore from it.
Expand All @@ -340,32 +353,19 @@ void android_main(struct android_app* state) {

while (true) {
// Read all pending events.
int ident;
int events;
struct android_poll_source* source;

// If not animating, we will block forever waiting for events.
// If animating, we loop until all events are read, then continue
// to draw the next frame of animation.
while ((ident = ALooper_pollAll(engine.animating ? 0 : -1, nullptr, &events,
(void**)&source)) >= 0) {
while ((ALooper_pollAll(engine.animating ? 0 : -1, nullptr, &events,
(void**)&source)) >= 0) {
// Process this event.
if (source != nullptr) {
source->process(state, source);
}

// If a sensor has data, process it now.
if (ident == LOOPER_ID_USER) {
if (engine.accelerometerSensor != nullptr) {
ASensorEvent event;
while (ASensorEventQueue_getEvents(engine.sensorEventQueue, &event,
1) > 0) {
LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x,
event.acceleration.y, event.acceleration.z);
}
}
}

// Check if we are exiting.
if (state->destroyRequested != 0) {
engine_term_display(&engine);
Expand Down
2 changes: 1 addition & 1 deletion other-builds/ndkbuild/native-activity/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {

defaultConfig {
applicationId = 'com.example.native_activity'
minSdkVersion 14
minSdkVersion 21
targetSdkVersion 33
}
sourceSets {
Expand Down
Loading