diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/input.h b/ndk/platforms/android-9/arch-arm/usr/include/android/input.h index 243c33c3a..5b62da443 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/input.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/input.h @@ -623,10 +623,10 @@ typedef struct AInputQueue AInputQueue; /* * Add this input queue to a looper for processing. See - * ALooper_addFd() for information on the callback and data params. + * ALooper_addFd() for information on the ident, callback, and data params. */ void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, - ALooper_callbackFunc* callback, void* data); + int ident, ALooper_callbackFunc* callback, void* data); /* * Remove the input queue from the looper it is currently attached to. @@ -662,64 +662,6 @@ int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); */ void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); -/* - * Input devices. - * - * These functions provide a mechanism for querying the set of available input devices - * and their characteristics and capabilities. - */ -struct AInputDevice; -typedef struct AInputDevice AInputDevice; - -/* - * Populates the supplied array with the ids of all input devices in the system. - * Sets nActual to the actual number of devices. - * Returns zero if enumeration was successful. - * Returns non-zero if the actual number of devices is greater than nMax, in which case the - * client should call the method again with a larger id buffer. - */ -int32_t AInputDevice_getDeviceIds(int32_t* idBuf, size_t nMax, size_t* nActual); - -/* - * Acquires a device by id. - * Returns NULL if the device was not found. - * - * Note: The returned object must be freed using AInputDevice_release when no longer needed. - */ -AInputDevice* AInputDevice_acquire(int32_t deviceId); - -/* - * Releases a device previously acquired by AInputDevice_acquire. - * If device is NULL, this function does nothing. - */ -void AInputDevice_release(AInputDevice* device); - -/* - * Gets the name of an input device. - * - * Note: The caller should copy the name into a private buffer since the returned pointer - * will become invalid when the device object is released. - */ -const char* AInputDevice_getName(AInputDevice* device); - -/* - * Gets the combination of input sources provided by the input device. - */ -uint32_t AInputDevice_getSources(AInputDevice* device); - -/* - * Gets the keyboard type. - */ -int32_t AInputDevice_getKeyboardType(AInputDevice* device); - -/* Gets the minimum value, maximum value, flat position and error tolerance for a - * particular motion coodinate. - * Returns zero if the device supports the specified motion range. */ -int32_t AInputDevice_getMotionRange(AInputDevice* device, int32_t rangeType, - float* outMin, float* outMax, float* outFlat, float* outFuzz); - -//TODO hasKey, keymap stuff, etc... - #ifdef __cplusplus } #endif diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/looper.h b/ndk/platforms/android-9/arch-arm/usr/include/android/looper.h index 291721624..287bcd5f0 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/looper.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/looper.h @@ -111,7 +111,7 @@ enum { * * Returns ALOPER_POLL_ERROR if an error occurred. * - * Returns a value >= 0 containing a file descriptor if it has data + * Returns a value >= 0 containing an identifier if its file descriptor has data * and it has no callback function (requiring the caller here to handle it). * In this (and only this) case outEvents and outData will contain the poll * events and data associated with the fd. @@ -145,10 +145,12 @@ void ALooper_release(ALooper* looper); * descriptor was previously added, it is replaced. * * "fd" is the file descriptor to be added. + * "ident" is an identifier for this event, which is returned from + * ALooper_pollOnce(). Must be >= 0, or ALOOPER_POLL_CALLBACK if + * providing a non-NULL callback. * "events" are the poll events to wake up on. Typically this is POLLIN. * "callback" is the function to call when there is an event on the file * descriptor. - * "id" is an identifier to associated with this file descriptor, or 0. * "data" is a private data pointer to supply to the callback. * * There are two main uses of this function: @@ -156,13 +158,13 @@ void ALooper_release(ALooper* looper); * (1) If "callback" is non-NULL, then * this function will be called when there is data on the file descriptor. It * should execute any events it has pending, appropriately reading from the - * file descriptor. + * file descriptor. The 'ident' is ignored in this case. * - * (2) If "callback" is NULL, the fd will be returned by ALooper_pollOnce - * when it has data available, requiring the caller to take care of processing - * it. + * (2) If "callback" is NULL, the 'ident' will be returned by ALooper_pollOnce + * when its file descriptor has data available, requiring the caller to take + * care of processing it. */ -void ALooper_addFd(ALooper* looper, int fd, int events, +void ALooper_addFd(ALooper* looper, int fd, int ident, int events, ALooper_callbackFunc* callback, void* data); /** diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h b/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h index b4ce02426..a102d43c7 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/sensor.h @@ -166,7 +166,7 @@ ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type * Creates a new sensor event queue and associate it with a looper. */ ASensorEventQueue* ASensorManager_createEventQueue(ASensorManager* manager, - ALooper* looper, ALooper_callbackFunc* callback, void* data); + ALooper* looper, int ident, ALooper_callbackFunc* callback, void* data); /* * Destroys the event queue and free all resources associated to it. diff --git a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so index 1b41c6758..2ca0227de 100644 Binary files a/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so and b/ndk/platforms/android-9/arch-arm/usr/lib/libandroid.so differ diff --git a/ndk/platforms/android-9/samples/native-activity/jni/main.c b/ndk/platforms/android-9/samples/native-activity/jni/main.c index 9d83f041f..378fd621f 100644 --- a/ndk/platforms/android-9/samples/native-activity/jni/main.c +++ b/ndk/platforms/android-9/samples/native-activity/jni/main.c @@ -17,9 +17,10 @@ //BEGIN_INCLUDE(all) #include - #include +#include + #include #include "glutils.h" @@ -39,6 +40,10 @@ struct saved_state { struct engine { struct android_app* app; + ASensorManager* sensorManager; + const ASensor* accelerometerSensor; + ASensorEventQueue* sensorEventQueue; + int animating; EGLDisplay display; EGLSurface surface; @@ -151,20 +156,40 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) { struct engine* engine = (struct engine*)app->userData; switch (cmd) { case APP_CMD_SAVE_STATE: + // The system has asked us to save our current state. Do so. engine->app->savedState = malloc(sizeof(struct saved_state)); *((struct saved_state*)engine->app->savedState) = engine->state; engine->app->savedStateSize = sizeof(struct saved_state); break; case APP_CMD_INIT_WINDOW: + // The window is being shown, get it ready. if (engine->app->window != NULL) { engine_init_display(engine); engine_draw_frame(engine); } break; case APP_CMD_TERM_WINDOW: + // The window is being hidden or closed, clean it up. engine_term_display(engine); break; + case APP_CMD_GAINED_FOCUS: + // When our app gains focus, we start monitoring the accelerometer. + if (engine->accelerometerSensor != NULL) { + ASensorEventQueue_enableSensor(engine->sensorEventQueue, + engine->accelerometerSensor); + // We'd like to get 60 events per second (in us). + ASensorEventQueue_setEventRate(engine->sensorEventQueue, + engine->accelerometerSensor, (1000L/60)*1000); + } + break; case APP_CMD_LOST_FOCUS: + // When our app loses focus, we stop monitoring the accelerometer. + // This is to avoid consuming battery while not being used. + if (engine->accelerometerSensor != NULL) { + ASensorEventQueue_disableSensor(engine->sensorEventQueue, + engine->accelerometerSensor); + } + // Also stop animating. engine->animating = 0; engine_draw_frame(engine); break; @@ -188,6 +213,13 @@ void android_main(struct android_app* state) { state->onInputEvent = engine_handle_input; 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, NULL, NULL); + if (state->savedState != NULL) { // We are starting with a previous saved state; restore from it. engine.state = *(struct saved_state*)state->savedState; @@ -197,19 +229,32 @@ void android_main(struct android_app* state) { while (1) { // Read all pending events. - int fd; + 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 ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, + while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, &events, (void**)&source)) >= 0) { // Process this event. if (source != NULL) { - source->process(state); + source->process(state, source); + } + + // If a sensor has data, process it now. + if (ident == LOOPER_ID_USER) { + if (engine.accelerometerSensor != NULL) { + 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. diff --git a/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c b/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c index 6d725ae89..c364f1813 100644 --- a/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c +++ b/ndk/platforms/android-9/samples/native-plasma/jni/plasma.c @@ -469,19 +469,19 @@ void android_main(struct android_app* state) { while (1) { // Read all pending events. - int fd; + 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 ((fd=ALooper_pollAll(engine.animating ? 0 : -1, &events, + while ((ident=ALooper_pollAll(engine.animating ? 0 : -1, &events, (void**)&source)) >= 0) { // Process this event. if (source != NULL) { - source->process(state); + source->process(state, source); } // Check if we are exiting. diff --git a/ndk/sources/android/native_app_glue/android_native_app_glue.c b/ndk/sources/android/native_app_glue/android_native_app_glue.c index 05c638ede..7888f7dc2 100644 --- a/ndk/sources/android/native_app_glue/android_native_app_glue.c +++ b/ndk/sources/android/native_app_glue/android_native_app_glue.c @@ -89,7 +89,8 @@ void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { if (android_app->inputQueue != NULL) { LOGI("Attaching input queue to looper"); AInputQueue_attachLooper(android_app->inputQueue, - android_app->looper, NULL, &android_app->inputPollSource); + android_app->looper, LOOPER_ID_INPUT, NULL, + &android_app->inputPollSource); } pthread_cond_broadcast(&android_app->cond); pthread_mutex_unlock(&android_app->mutex); @@ -178,7 +179,7 @@ static void android_app_destroy(struct android_app* android_app) { // Can't touch android_app object after this. } -static void process_input(struct android_app* app) { +static void process_input(struct android_app* app, struct android_poll_source* source) { AInputEvent* event = NULL; if (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { LOGI("New input event: type=%d\n", AInputEvent_getType(event)); @@ -193,7 +194,7 @@ static void process_input(struct android_app* app) { } } -static void process_cmd(struct android_app* app) { +static void process_cmd(struct android_app* app, struct android_poll_source* source) { int8_t cmd = android_app_read_cmd(app); android_app_pre_exec_cmd(app, cmd); if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); @@ -216,7 +217,8 @@ static void* android_app_entry(void* param) { android_app->inputPollSource.process = process_input; ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, &android_app->cmdPollSource); + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, POLLIN, NULL, + &android_app->cmdPollSource); android_app->looper = looper; pthread_mutex_lock(&android_app->mutex); diff --git a/ndk/sources/android/native_app_glue/android_native_app_glue.h b/ndk/sources/android/native_app_glue/android_native_app_glue.h index e60f1c079..321299cac 100644 --- a/ndk/sources/android/native_app_glue/android_native_app_glue.h +++ b/ndk/sources/android/native_app_glue/android_native_app_glue.h @@ -59,25 +59,26 @@ extern "C" * * - input events coming from the AInputQueue attached to the activity. * - * Each of these correspond to an ALooper callback that returns a "data" - * value of LOOPER_ID_MAIN and LOOPER_ID_INPUT, respectively. + * Each of these correspond to an ALooper identifier returned by + * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, + * respectively. * - * Your application can use the same ALooper to listen to additionnal - * file-descriptors. + * Your application can use the same ALooper to listen to additional + * file-descriptors. They can either be callback based, or with return + * identifiers starting with LOOPER_ID_USER. * - * 4/ Whenever you receive a LOOPER_ID_MAIN event from the ALooper, your - * code should call the function android_app_read_cmd() to read the - * command value and act upon it. This is normally done by calling - * android_app_exec_cmd() directly. + * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event, + * the returned data will point to an android_poll_source structure. You + * can call the process() function on it, and fill in android_app->onAppCmd + * and android_app->onInputEvent to be called for your own processing + * of the event. * - * XXX: MAKE THIS STUFF MORE CLEAR !! - * - * 5/ Whenever you receive a LOOPER_ID_INPUT event from the ALooper, you - * should read one event from the AInputQueue with AInputQueue_getEvent(). + * Alternatively, you can call the low-level functions to read and process + * the data directly... look at the process_cmd() and process_input() + * implementations in the glue to see how to do this. * * See the sample named "native-activity" that comes with the NDK with a - * full usage example. - * + * full usage example. Also look at the JavaDoc of NativeActivity. */ struct android_app; @@ -91,12 +92,12 @@ struct android_poll_source { // LOOPER_ID_INPUT. int32_t id; - // The android_app this fd is associated with. + // The android_app this ident is associated with. struct android_app* app; // Function to call to perform the standard processing of data from // this source. - void (*process)(struct android_app* app); + void (*process)(struct android_app* app, struct android_poll_source* source); }; /** @@ -185,7 +186,9 @@ struct android_app { enum { /** - * Looper data ID of commands coming from the app's main thread. + * Looper data ID of commands coming from the app's main thread, which + * is returned as an identifier from ALooper_pollOnce(). The data for this + * identifier is a pointer to an android_poll_source structure. * These can be retrieved and processed with android_app_read_cmd() * and android_app_exec_cmd(). */ @@ -193,10 +196,17 @@ enum { /** * Looper data ID of events coming from the AInputQueue of the - * application's window. These can be read via the inputQueue + * application's window, which is returned as an identifier from + * ALooper_pollOnce(). The data for this identifier is a pointer to an + * android_poll_source structure. These can be read via the inputQueue * object of android_app. */ - LOOPER_ID_INPUT = 2 + LOOPER_ID_INPUT = 2, + + /** + * Start of user-defined ALooper identifiers. + */ + LOOPER_ID_USER = 3, }; enum {