Skip to content

Commit

Permalink
Move sensor handling to a callback.
Browse files Browse the repository at this point in the history
The apparent change in `minSdkVersion` here isn't actually changing
much. The NDK hasn't supported ICS in a long time, and 21 is the minimum
for modern NDKs (though I think this sample is still using an NDK that
supports 19, it won't soon). The raise is needed for
android_set_abort_message.
  • Loading branch information
DanAlbert committed May 1, 2024
1 parent b79af2b commit cbec281
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 22 deletions.
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
81 changes: 61 additions & 20 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 @@ -35,9 +36,34 @@
#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");
} 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 All @@ -64,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 @@ -269,6 +309,24 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
}
}

int OnSensorEvent(int /* fd */, int /* events */, void* data) {
CHECK_NOT_NULL(data);
engine* engine = reinterpret_cast<struct engine*>(data);

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);
}

// 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;
}

/**
* This is the main entry point of a native application that is using
* android_native_app_glue. It runs in its own thread, with its own
Expand All @@ -284,11 +342,7 @@ void android_main(struct android_app* state) {
engine.app = state;

// Prepare to monitor accelerometer
engine.sensorManager = ASensorManager_getInstance();
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 @@ -299,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

0 comments on commit cbec281

Please sign in to comment.