Skip to content

Commit cbec281

Browse files
committed
Move sensor handling to a callback.
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.
1 parent b79af2b commit cbec281

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

native-activity/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ android {
1212

1313
defaultConfig {
1414
applicationId = 'com.example.native_activity'
15-
minSdkVersion 14
15+
minSdkVersion 21
1616
targetSdkVersion 34
1717
externalNativeBuild {
1818
cmake {

native-activity/app/src/main/cpp/main.cpp

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <GLES/gl.h>
2121
#include <android/log.h>
2222
#include <android/sensor.h>
23+
#include <android/set_abort_message.h>
2324
#include <android_native_app_glue.h>
2425
#include <jni.h>
2526

@@ -35,9 +36,34 @@
3536
#define _LOG(priority, fmt, ...) \
3637
((void)__android_log_print((priority), (LOG_TAG), (fmt)__VA_OPT__(, ) __VA_ARGS__))
3738

39+
#define LOGE(fmt, ...) _LOG(ANDROID_LOG_ERROR, (fmt)__VA_OPT__(, ) __VA_ARGS__)
3840
#define LOGW(fmt, ...) _LOG(ANDROID_LOG_WARN, (fmt)__VA_OPT__(, ) __VA_ARGS__)
3941
#define LOGI(fmt, ...) _LOG(ANDROID_LOG_INFO, (fmt)__VA_OPT__(, ) __VA_ARGS__)
4042

43+
[[noreturn]] __attribute__((__format__(__printf__, 1, 2))) static void fatal(
44+
const char* fmt, ...) {
45+
va_list ap;
46+
va_start(ap, fmt);
47+
char* buf;
48+
if (vasprintf(&buf, fmt, ap) < 0) {
49+
android_set_abort_message("failed for format error message");
50+
} else {
51+
android_set_abort_message(buf);
52+
// Also log directly, since the default Android Studio logcat filter hides
53+
// the backtrace which would otherwise show the abort message.
54+
LOGE("%s", buf);
55+
}
56+
std::abort();
57+
}
58+
59+
#define CHECK_NOT_NULL(value) \
60+
do { \
61+
if ((value) == nullptr) { \
62+
fatal("%s:%d:%s must not be null", __PRETTY_FUNCTION__, __LINE__, \
63+
#value); \
64+
} \
65+
} while (false)
66+
4167
/**
4268
* Our saved state data.
4369
*/
@@ -64,6 +90,20 @@ struct engine {
6490
int32_t width;
6591
int32_t height;
6692
struct saved_state state;
93+
94+
void CreateSensorListener(ALooper_callbackFunc callback) {
95+
CHECK_NOT_NULL(app);
96+
97+
sensorManager = ASensorManager_getInstance();
98+
if (sensorManager == nullptr) {
99+
return;
100+
}
101+
102+
accelerometerSensor = ASensorManager_getDefaultSensor(
103+
sensorManager, ASENSOR_TYPE_ACCELEROMETER);
104+
sensorEventQueue = ASensorManager_createEventQueue(
105+
sensorManager, app->looper, ALOOPER_POLL_CALLBACK, callback, this);
106+
}
67107
};
68108

69109
/**
@@ -269,6 +309,24 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
269309
}
270310
}
271311

312+
int OnSensorEvent(int /* fd */, int /* events */, void* data) {
313+
CHECK_NOT_NULL(data);
314+
engine* engine = reinterpret_cast<struct engine*>(data);
315+
316+
CHECK_NOT_NULL(engine->accelerometerSensor);
317+
ASensorEvent event;
318+
while (ASensorEventQueue_getEvents(engine->sensorEventQueue, &event, 1) > 0) {
319+
LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x,
320+
event.acceleration.y, event.acceleration.z);
321+
}
322+
323+
// From the docs:
324+
//
325+
// Implementations should return 1 to continue receiving callbacks, or 0 to
326+
// have this file descriptor and callback unregistered from the looper.
327+
return 1;
328+
}
329+
272330
/**
273331
* This is the main entry point of a native application that is using
274332
* android_native_app_glue. It runs in its own thread, with its own
@@ -284,11 +342,7 @@ void android_main(struct android_app* state) {
284342
engine.app = state;
285343

286344
// Prepare to monitor accelerometer
287-
engine.sensorManager = ASensorManager_getInstance();
288-
engine.accelerometerSensor = ASensorManager_getDefaultSensor(
289-
engine.sensorManager, ASENSOR_TYPE_ACCELEROMETER);
290-
engine.sensorEventQueue = ASensorManager_createEventQueue(
291-
engine.sensorManager, state->looper, LOOPER_ID_USER, nullptr, nullptr);
345+
engine.CreateSensorListener(OnSensorEvent);
292346

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

300354
while (true) {
301355
// Read all pending events.
302-
int ident;
303356
int events;
304357
struct android_poll_source* source;
305358

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

316-
// If a sensor has data, process it now.
317-
if (ident == LOOPER_ID_USER) {
318-
if (engine.accelerometerSensor != nullptr) {
319-
ASensorEvent event;
320-
while (ASensorEventQueue_getEvents(engine.sensorEventQueue, &event,
321-
1) > 0) {
322-
LOGI("accelerometer: x=%f y=%f z=%f", event.acceleration.x,
323-
event.acceleration.y, event.acceleration.z);
324-
}
325-
}
326-
}
327-
328369
// Check if we are exiting.
329370
if (state->destroyRequested != 0) {
330371
engine_term_display(&engine);

other-builds/ndkbuild/native-activity/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ android {
1212

1313
defaultConfig {
1414
applicationId = 'com.example.native_activity'
15-
minSdkVersion 14
15+
minSdkVersion 21
1616
targetSdkVersion 33
1717
}
1818
sourceSets {

0 commit comments

Comments
 (0)