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 76176624a..75be85abb 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 @@ -42,6 +42,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -533,12 +534,15 @@ struct AInputQueue; typedef struct AInputQueue AInputQueue; /* - * Return a file descriptor for the queue, which you - * can use to determine if there are events available. This - * is typically used with select() or poll() to multiplex - * with other kinds of events. + * Add this input queue to a looper for processing. */ -int AInputQueue_getFd(AInputQueue* queue); +void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, + ALooper_callbackFunc callback, void* data); + +/* + * Remove the input queue from the looper it is currently attached to. + */ +void AInputQueue_detachLooper(AInputQueue* queue); /* * Returns true if there are one or more events available in the 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 new file mode 100644 index 000000000..90a89838a --- /dev/null +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/looper.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef ANDROID_LOOPER_H +#define ANDROID_LOOPER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ALooper; +typedef struct ALooper ALooper; + +typedef int ALooper_callbackFunc(int fd, int events, void* data); + +ALooper* ALooper_forThread(); + +ALooper* ALooper_prepare(); + +int32_t ALooper_pollOnce(int timeoutMillis); + +void ALooper_acquire(ALooper* looper); + +void ALooper_release(ALooper* looper); + +void ALooper_setCallback(ALooper* looper, int fd, int events, + ALooper_callbackFunc* callback, void* data); + +int32_t ALooper_removeCallback(ALooper* looper, int fd); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_WINDOW_H diff --git a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h index bf5c641fc..a31c5af74 100644 --- a/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h +++ b/ndk/platforms/android-9/arch-arm/usr/include/android/native_activity.h @@ -63,6 +63,21 @@ typedef struct ANativeActivity { */ jobject clazz; + /** + * Path to this application's internal data directory. + */ + const char* internalDataPath; + + /** + * Path to this application's external (removable/mountable) data directory. + */ + const char* externalDataPath; + + /** + * The platform's SDK version code. + */ + int32_t sdkVersion; + /** * This is the native instance of the application. It is not used by * the framework, but can be set by the application to its own instance 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 ffef23da8..d185a8fb1 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/samples/native-activity/jni/glutils.c b/ndk/samples/native-activity/jni/glutils.c index 372e72e3e..fcd2d880a 100644 --- a/ndk/samples/native-activity/jni/glutils.c +++ b/ndk/samples/native-activity/jni/glutils.c @@ -17,6 +17,8 @@ #include "glutils.h" +#include + const char *EGLstrerror(EGLint err) { switch (err) { case EGL_SUCCESS: return "EGL_SUCCESS"; diff --git a/ndk/samples/native-activity/jni/main.c b/ndk/samples/native-activity/jni/main.c index 0b784154a..3d2faeef9 100644 --- a/ndk/samples/native-activity/jni/main.c +++ b/ndk/samples/native-activity/jni/main.c @@ -42,12 +42,14 @@ struct engine { int running; int destroyed; + ALooper* looper; AInputQueue* inputQueue; ANativeWindow* window; AInputQueue* pendingInputQueue; ANativeWindow* pendingWindow; // private to engine thread. + int destroyRequested; int animating; EGLDisplay display; EGLSurface surface; @@ -159,105 +161,121 @@ static int engine_term_display(struct engine* engine) { engine->surface = EGL_NO_SURFACE; } +static int engine_process_event(int fd, int events, void* param) { + struct engine* engine = (struct engine*)param; + + AInputEvent* event = NULL; + if (AInputQueue_getEvent(engine->inputQueue, &event) >= 0) { + LOGI("New input event: type=%d\n", AInputEvent_getType(event)); + if (AInputEvent_getType(event) == INPUT_EVENT_TYPE_MOTION) { + engine->animating = 1; + engine->x = AMotionEvent_getX(event, 0); + engine->y = AMotionEvent_getY(event, 0); + AInputQueue_finishEvent(engine->inputQueue, event, 1); + } else { + AInputQueue_finishEvent(engine->inputQueue, event, 0); + } + } else { + LOGI("Failure reading next input event: %s\n", strerror(errno)); + } + + return 1; +} + +static int engine_process_cmd(int fd, int events, void* param) { + struct engine* engine = (struct engine*)param; + + int8_t cmd; + if (read(engine->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { + switch (cmd) { + case ENGINE_CMD_INPUT_CHANGED: + LOGI("Engine: ENGINE_CMD_INPUT_CHANGED\n"); + pthread_mutex_lock(&engine->mutex); + if (engine->inputQueue != NULL) { + AInputQueue_detachLooper(engine->inputQueue); + } + engine->inputQueue = engine->pendingInputQueue; + if (engine->inputQueue != NULL) { + LOGI("Attaching input queue to looper"); + AInputQueue_attachLooper(engine->inputQueue, + engine->looper, engine_process_event, engine); + } + pthread_cond_broadcast(&engine->cond); + pthread_mutex_unlock(&engine->mutex); + break; + + case ENGINE_CMD_WINDOW_CHANGED: + LOGI("Engine: ENGINE_CMD_WINDOW_CHANGED\n"); + engine_term_display(engine); + pthread_mutex_lock(&engine->mutex); + engine->window = engine->pendingWindow; + pthread_cond_broadcast(&engine->cond); + pthread_mutex_unlock(&engine->mutex); + if (engine->window != NULL) { + engine_init_display(engine); + engine_draw_frame(engine); + } + break; + + case ENGINE_CMD_LOST_FOCUS: + engine->animating = 0; + engine_draw_frame(engine); + break; + + case ENGINE_CMD_DESTROY: + LOGI("Engine: ENGINE_CMD_DESTROY\n"); + engine->destroyRequested = 1; + break; + } + } else { + LOGW("No data on command pipe!"); + } + + return 1; +} + static void* engine_entry(void* param) { struct engine* engine = (struct engine*)param; - struct pollfd pfd[2]; - int numfd; + + ALooper* looper = ALooper_prepare(); + ALooper_setCallback(looper, engine->msgread, POLLIN, engine_process_cmd, engine); + engine->looper = looper; pthread_mutex_lock(&engine->mutex); engine->running = 1; pthread_cond_broadcast(&engine->cond); pthread_mutex_unlock(&engine->mutex); - // loop waiting for stuff to do. we wait for input events or - // commands from the main thread. - - pfd[0].fd = engine->msgread; - pfd[0].events = POLLIN; - pfd[0].revents = 0; + // loop waiting for stuff to do. while (1) { - if (engine->inputQueue != NULL) { - numfd = 2; - pfd[1].fd = AInputQueue_getFd(engine->inputQueue); - pfd[1].events = POLLIN; - } else { - numfd = 1; + // Read all pending events. + while (ALooper_pollOnce(engine->animating ? 0 : -1)) { + ; } - pfd[0].revents = 0; - pfd[1].revents = 0; - int nfd = poll(pfd, numfd, engine->animating ? 0 : -1); - if (nfd == 0 && engine->animating) { - // There is no work to do -- step next animation. + if (engine->destroyRequested) { + LOGI("Engine thread destroy requested!"); + pthread_mutex_lock(&engine->mutex); + engine_term_display(engine); + if (engine->inputQueue != NULL) { + AInputQueue_detachLooper(engine->inputQueue); + } + engine->destroyed = 1; + pthread_cond_broadcast(&engine->cond); + pthread_mutex_unlock(&engine->mutex); + // Can't touch engine object after this. + return NULL; // EXIT THREAD + } + + if (engine->animating) { + // Done with events; draw next animation frame. engine->angle += .01f; if (engine->angle > 1) { engine->angle = 0; } engine_draw_frame(engine); } - if (nfd < 0) { - LOGI("Engine error in poll: %s\n", strerror(errno)); - // Should cleanly exit! - continue; - } - - if (pfd[0].revents == POLLIN) { - int8_t cmd; - if (read(engine->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { - switch (cmd) { - case ENGINE_CMD_INPUT_CHANGED: - LOGI("Engine: ENGINE_CMD_INPUT_CHANGED\n"); - pthread_mutex_lock(&engine->mutex); - engine->inputQueue = engine->pendingInputQueue; - pthread_cond_broadcast(&engine->cond); - pthread_mutex_unlock(&engine->mutex); - break; - case ENGINE_CMD_WINDOW_CHANGED: - LOGI("Engine: ENGINE_CMD_WINDOW_CHANGED\n"); - pthread_mutex_lock(&engine->mutex); - engine_term_display(engine); - engine->window = engine->pendingWindow; - if (engine->window != NULL) { - engine_init_display(engine); - engine_draw_frame(engine); - } - pthread_cond_broadcast(&engine->cond); - pthread_mutex_unlock(&engine->mutex); - break; - case ENGINE_CMD_LOST_FOCUS: - engine->animating = 0; - engine_draw_frame(engine); - break; - case ENGINE_CMD_DESTROY: - LOGI("Engine: ENGINE_CMD_DESTROY\n"); - pthread_mutex_lock(&engine->mutex); - engine_term_display(engine); - engine->destroyed = 1; - pthread_cond_broadcast(&engine->cond); - pthread_mutex_unlock(&engine->mutex); - // Can't touch engine object after this. - return NULL; // EXIT THREAD - } - } else { - LOGI("Failure reading engine cmd: %s\n", strerror(errno)); - } - - } else if (engine->inputQueue != NULL && pfd[1].revents == POLLIN) { - AInputEvent* event = NULL; - if (AInputQueue_getEvent(engine->inputQueue, &event) >= 0) { - LOGI("New input event: type=%d\n", AInputEvent_getType(event)); - if (AInputEvent_getType(event) == INPUT_EVENT_TYPE_MOTION) { - engine->animating = 1; - engine->x = AMotionEvent_getX(event, 0); - engine->y = AMotionEvent_getY(event, 0); - engine_draw_frame(engine); - } - AInputQueue_finishEvent(engine->inputQueue, event, 0); - } else { - LOGI("Failure reading next input event: %s\n", strerror(errno)); - } - } } } @@ -329,6 +347,7 @@ static void engine_destroy(struct engine* engine) { close(engine->msgwrite); pthread_cond_destroy(&engine->cond); pthread_mutex_destroy(&engine->mutex); + free(engine); } // -------------------------------------------------------------------- diff --git a/ndk/samples/native-activity/src/Dummy.java b/ndk/samples/native-activity/src/Dummy.java new file mode 100644 index 000000000..4160c66b9 --- /dev/null +++ b/ndk/samples/native-activity/src/Dummy.java @@ -0,0 +1,4 @@ + +// Only needed for the build system. +public class Dummy { +}