diff options
Diffstat (limited to 'native')
-rw-r--r-- | native/android/Android.mk | 7 | ||||
-rw-r--r-- | native/android/activity.cpp | 0 | ||||
-rw-r--r-- | native/android/input.cpp | 4 | ||||
-rw-r--r-- | native/android/looper.cpp | 31 | ||||
-rw-r--r-- | native/android/native_activity.cpp | 31 | ||||
-rw-r--r-- | native/android/native_window.cpp | 58 | ||||
-rw-r--r-- | native/glue/threaded_app/Android.mk | 18 | ||||
-rw-r--r-- | native/glue/threaded_app/threaded_app.c | 279 | ||||
-rw-r--r-- | native/include/android/input.h | 5 | ||||
-rw-r--r-- | native/include/android/looper.h | 134 | ||||
-rw-r--r-- | native/include/android/native_activity.h | 5 | ||||
-rw-r--r-- | native/include/android/native_window.h | 43 | ||||
-rw-r--r-- | native/include/android/native_window_jni.h | 40 | ||||
-rw-r--r-- | native/include/android/rect.h | 36 | ||||
-rw-r--r-- | native/include/android/window.h | 58 | ||||
-rw-r--r-- | native/include/android_glue/threaded_app.h | 165 |
16 files changed, 887 insertions, 27 deletions
diff --git a/native/android/Android.mk b/native/android/Android.mk index 376c64f..509a379 100644 --- a/native/android/Android.mk +++ b/native/android/Android.mk @@ -6,17 +6,18 @@ include $(CLEAR_VARS) # our source files # LOCAL_SRC_FILES:= \ - activity.cpp \ input.cpp \ looper.cpp \ + native_activity.cpp \ native_window.cpp LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ libcutils \ libutils \ libbinder \ - libui + libui \ + libsurfaceflinger_client \ + libandroid_runtime LOCAL_C_INCLUDES += \ frameworks/base/native/include \ diff --git a/native/android/activity.cpp b/native/android/activity.cpp deleted file mode 100644 index e69de29..0000000 --- a/native/android/activity.cpp +++ /dev/null diff --git a/native/android/input.cpp b/native/android/input.cpp index 015a1ce..89d53e2 100644 --- a/native/android/input.cpp +++ b/native/android/input.cpp @@ -186,9 +186,9 @@ float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_i } void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, - ALooper_callbackFunc callback, void* data) { + ALooper_callbackFunc* callback, void* data) { queue->setPollLoop(static_cast<android::PollLoop*>(looper)); - ALooper_setCallback(looper, queue->getConsumer().getChannel()->getReceivePipeFd(), + ALooper_addFd(looper, queue->getConsumer().getChannel()->getReceivePipeFd(), POLLIN, callback, data); } diff --git a/native/android/looper.cpp b/native/android/looper.cpp index 6e78bbd..1564c47 100644 --- a/native/android/looper.cpp +++ b/native/android/looper.cpp @@ -27,22 +27,41 @@ ALooper* ALooper_forThread() { return PollLoop::getForThread().get(); } -ALooper* ALooper_prepare() { +ALooper* ALooper_prepare(int32_t opts) { + bool allowFds = (opts&ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) != 0; sp<PollLoop> loop = PollLoop::getForThread(); if (loop == NULL) { - loop = new PollLoop(); + loop = new PollLoop(allowFds); PollLoop::setForThread(loop); } + if (loop->getAllowNonCallbacks() != allowFds) { + LOGW("ALooper_prepare again with different ALOOPER_PREPARE_ALLOW_NON_CALLBACKS"); + } return loop.get(); } -int32_t ALooper_pollOnce(int timeoutMillis) { +int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData) { sp<PollLoop> loop = PollLoop::getForThread(); if (loop == NULL) { LOGW("ALooper_pollOnce: No looper for this thread!"); return -1; } - return loop->pollOnce(timeoutMillis) ? 1 : 0; + return loop->pollOnce(timeoutMillis, outEvents, outData); +} + +int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData) { + sp<PollLoop> loop = PollLoop::getForThread(); + if (loop == NULL) { + LOGW("ALooper_pollOnce: No looper for this thread!"); + return -1; + } + + int32_t result; + while ((result = loop->pollOnce(timeoutMillis, outEvents, outData)) == ALOOPER_POLL_CALLBACK) { + ; + } + + return result; } void ALooper_acquire(ALooper* looper) { @@ -53,11 +72,11 @@ void ALooper_release(ALooper* looper) { static_cast<PollLoop*>(looper)->decStrong((void*)ALooper_acquire); } -void ALooper_setCallback(ALooper* looper, int fd, int events, +void ALooper_addFd(ALooper* looper, int fd, int events, ALooper_callbackFunc* callback, void* data) { static_cast<PollLoop*>(looper)->setLooperCallback(fd, events, callback, data); } -int32_t ALooper_removeCallback(ALooper* looper, int fd) { +int32_t ALooper_removeFd(ALooper* looper, int fd) { return static_cast<PollLoop*>(looper)->removeCallback(fd) ? 1 : 0; } diff --git a/native/android/native_activity.cpp b/native/android/native_activity.cpp new file mode 100644 index 0000000..509cc33 --- /dev/null +++ b/native/android/native_activity.cpp @@ -0,0 +1,31 @@ +/* + * 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. + */ + +#define LOG_TAG "native_activity" +#include <utils/Log.h> + +#include <android_runtime/android_app_NativeActivity.h> + +using namespace android; + +void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format) { + android_NativeActivity_setWindowFormat(activity, format); +} + +void ANativeActivity_setWindowFlags(ANativeActivity* activity, + uint32_t addFlags, uint32_t removeFlags) { + android_NativeActivity_setWindowFlags(activity, addFlags, addFlags|removeFlags); +} diff --git a/native/android/native_window.cpp b/native/android/native_window.cpp index 448cbfc..bada078 100644 --- a/native/android/native_window.cpp +++ b/native/android/native_window.cpp @@ -17,10 +17,27 @@ #define LOG_TAG "Surface" #include <utils/Log.h> -#include <android/native_window.h> +#include <android/native_window_jni.h> #include <surfaceflinger/Surface.h> +#include <android_runtime/android_view_Surface.h> -using android::Surface; +using namespace android; + +ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface) { + sp<ANativeWindow> win = android_Surface_getNativeWindow(env, surface); + if (win != NULL) { + win->incStrong((void*)ANativeWindow_acquire); + } + return win.get(); +} + +void ANativeWindow_acquire(ANativeWindow* window) { + window->incStrong((void*)ANativeWindow_acquire); +} + +void ANativeWindow_release(ANativeWindow* window) { + window->decStrong((void*)ANativeWindow_acquire); +} static int32_t getWindowProp(ANativeWindow* window, int what) { int value; @@ -41,7 +58,40 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window) { } int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, - int32_t height, int32_t format) { - native_window_set_buffers_geometry(window, width, height, format); + int32_t height) { + native_window_set_buffers_geometry(window, width, height, 0); return 0; } + +int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, + ARect* inOutDirtyBounds) { + Region dirtyRegion; + Region* dirtyParam = NULL; + if (inOutDirtyBounds != NULL) { + dirtyRegion.set(*(Rect*)inOutDirtyBounds); + dirtyParam = &dirtyRegion; + } + + Surface::SurfaceInfo info; + status_t res = static_cast<Surface*>(window)->lock(&info, dirtyParam); + if (res != OK) { + return -1; + } + + outBuffer->width = (int32_t)info.w; + outBuffer->height = (int32_t)info.h; + outBuffer->stride = (int32_t)info.s; + outBuffer->format = (int32_t)info.format; + outBuffer->bits = info.bits; + + if (inOutDirtyBounds != NULL) { + *inOutDirtyBounds = dirtyRegion.getBounds(); + } + + return 0; +} + +int32_t ANativeWindow_unlockAndPost(ANativeWindow* window) { + status_t res = static_cast<Surface*>(window)->unlockAndPost(); + return res == android::OK ? 0 : -1; +} diff --git a/native/glue/threaded_app/Android.mk b/native/glue/threaded_app/Android.mk new file mode 100644 index 0000000..cfc9b2a --- /dev/null +++ b/native/glue/threaded_app/Android.mk @@ -0,0 +1,18 @@ +BASE_PATH := $(call my-dir) +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +# our source files +# +LOCAL_SRC_FILES:= \ + threaded_app.c + +LOCAL_C_INCLUDES += \ + frameworks/base/native/include \ + frameworks/base/core/jni/android \ + dalvik/libnativehelper/include/nativehelper + +LOCAL_MODULE:= libthreaded_app + +include $(BUILD_STATIC_LIBRARY) diff --git a/native/glue/threaded_app/threaded_app.c b/native/glue/threaded_app/threaded_app.c new file mode 100644 index 0000000..2411e93 --- /dev/null +++ b/native/glue/threaded_app/threaded_app.c @@ -0,0 +1,279 @@ +/* + * 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. + * + */ + +#include <jni.h> + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/resource.h> + +#include <android_glue/threaded_app.h> + +#include <android/log.h> + +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) +#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "threaded_app", __VA_ARGS__)) + +int8_t android_app_read_cmd(struct android_app* android_app) { + int8_t cmd; + if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { + return cmd; + } else { + LOGW("No data on command pipe!"); + } + return -1; +} + +int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd) { + switch (cmd) { + case APP_CMD_INPUT_CHANGED: + LOGI("APP_CMD_INPUT_CHANGED\n"); + pthread_mutex_lock(&android_app->mutex); + if (android_app->inputQueue != NULL) { + AInputQueue_detachLooper(android_app->inputQueue); + } + android_app->inputQueue = android_app->pendingInputQueue; + if (android_app->inputQueue != NULL) { + LOGI("Attaching input queue to looper"); + AInputQueue_attachLooper(android_app->inputQueue, + android_app->looper, NULL, (void*)LOOPER_ID_EVENT); + } + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_WINDOW_CHANGED: + LOGI("APP_CMD_WINDOW_CHANGED\n"); + pthread_mutex_lock(&android_app->mutex); + android_app->window = android_app->pendingWindow; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_START: + case APP_CMD_RESUME: + case APP_CMD_PAUSE: + case APP_CMD_STOP: + LOGI("activityState=%d\n", cmd); + pthread_mutex_lock(&android_app->mutex); + android_app->activityState = cmd; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + break; + + case APP_CMD_DESTROY: + LOGI("APP_CMD_DESTROY\n"); + android_app->destroyRequested = 1; + break; + } + + return android_app->destroyRequested ? 0 : 1; +} + +static void android_app_destroy(struct android_app* android_app) { + LOGI("android_app_destroy!"); + pthread_mutex_lock(&android_app->mutex); + if (android_app->inputQueue != NULL) { + AInputQueue_detachLooper(android_app->inputQueue); + } + android_app->destroyed = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + // Can't touch android_app object after this. +} + +static void* android_app_entry(void* param) { + struct android_app* android_app = (struct android_app*)param; + + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); + ALooper_addFd(looper, android_app->msgread, POLLIN, NULL, (void*)LOOPER_ID_MAIN); + android_app->looper = looper; + + pthread_mutex_lock(&android_app->mutex); + android_app->running = 1; + pthread_cond_broadcast(&android_app->cond); + pthread_mutex_unlock(&android_app->mutex); + + android_main(android_app); + + android_app_destroy(android_app); + return NULL; +} + +// -------------------------------------------------------------------- +// Native activity interaction (called from main thread) +// -------------------------------------------------------------------- + +static struct android_app* android_app_create(ANativeActivity* activity) { + struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); + memset(android_app, 0, sizeof(struct android_app)); + android_app->activity = activity; + + pthread_mutex_init(&android_app->mutex, NULL); + pthread_cond_init(&android_app->cond, NULL); + + int msgpipe[2]; + if (pipe(msgpipe)) { + LOGI("could not create pipe: %s", strerror(errno)); + } + android_app->msgread = msgpipe[0]; + android_app->msgwrite = msgpipe[1]; + + pthread_attr_t attr; + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_create(&android_app->thread, &attr, android_app_entry, android_app); + + // Wait for thread to start. + pthread_mutex_lock(&android_app->mutex); + while (!android_app->running) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); + + return android_app; +} + +static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { + if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { + LOGI("Failure writing android_app cmd: %s\n", strerror(errno)); + } +} + +static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { + pthread_mutex_lock(&android_app->mutex); + android_app->pendingInputQueue = inputQueue; + android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); + while (android_app->inputQueue != android_app->pendingInputQueue) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); +} + +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { + pthread_mutex_lock(&android_app->mutex); + android_app->pendingWindow = window; + android_app_write_cmd(android_app, APP_CMD_WINDOW_CHANGED); + while (android_app->window != android_app->pendingWindow) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); +} + +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { + pthread_mutex_lock(&android_app->mutex); + android_app_write_cmd(android_app, cmd); + while (android_app->activityState != cmd) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); +} + +static void android_app_free(struct android_app* android_app) { + pthread_mutex_lock(&android_app->mutex); + android_app_write_cmd(android_app, APP_CMD_DESTROY); + while (!android_app->destroyed) { + pthread_cond_wait(&android_app->cond, &android_app->mutex); + } + pthread_mutex_unlock(&android_app->mutex); + + close(android_app->msgread); + close(android_app->msgwrite); + pthread_cond_destroy(&android_app->cond); + pthread_mutex_destroy(&android_app->mutex); + free(android_app); +} + +static void onDestroy(ANativeActivity* activity) { + LOGI("Destroy: %p\n", activity); + android_app_free((struct android_app*)activity->instance); +} + +static void onStart(ANativeActivity* activity) { + LOGI("Start: %p\n", activity); + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); +} + +static void onResume(ANativeActivity* activity) { + LOGI("Resume: %p\n", activity); + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); +} + +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { + LOGI("SaveInstanceState: %p\n", activity); + return NULL; +} + +static void onPause(ANativeActivity* activity) { + LOGI("Pause: %p\n", activity); + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); +} + +static void onStop(ANativeActivity* activity) { + LOGI("Stop: %p\n", activity); + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); +} + +static void onLowMemory(ANativeActivity* activity) { + LOGI("LowMemory: %p\n", activity); +} + +static void onWindowFocusChanged(ANativeActivity* activity, int focused) { + LOGI("WindowFocusChanged: %p -- %d\n", activity, focused); + android_app_write_cmd((struct android_app*)activity->instance, + focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); +} + +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { + LOGI("NativeWindowCreated: %p -- %p\n", activity, window); + android_app_set_window((struct android_app*)activity->instance, window); +} + +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { + LOGI("NativeWindowDestroyed: %p -- %p\n", activity, window); + android_app_set_window((struct android_app*)activity->instance, NULL); +} + +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { + LOGI("InputQueueCreated: %p -- %p\n", activity, queue); + android_app_set_input((struct android_app*)activity->instance, queue); +} + +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { + LOGI("InputQueueDestroyed: %p -- %p\n", activity, queue); + android_app_set_input((struct android_app*)activity->instance, NULL); +} + +void ANativeActivity_onCreate(ANativeActivity* activity, + void* savedState, size_t savedStateSize) { + LOGI("Creating: %p\n", activity); + activity->callbacks->onDestroy = onDestroy; + activity->callbacks->onStart = onStart; + activity->callbacks->onResume = onResume; + activity->callbacks->onSaveInstanceState = onSaveInstanceState; + activity->callbacks->onPause = onPause; + activity->callbacks->onStop = onStop; + activity->callbacks->onLowMemory = onLowMemory; + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; + activity->callbacks->onInputQueueCreated = onInputQueueCreated; + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; + + activity->instance = android_app_create(activity); +} diff --git a/native/include/android/input.h b/native/include/android/input.h index 75be85a..014b6a3 100644 --- a/native/include/android/input.h +++ b/native/include/android/input.h @@ -534,10 +534,11 @@ struct AInputQueue; typedef struct AInputQueue AInputQueue; /* - * Add this input queue to a looper for processing. + * Add this input queue to a looper for processing. See + * ALooper_addFd() for information on the callback and data params. */ void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, - ALooper_callbackFunc callback, void* data); + ALooper_callbackFunc* callback, void* data); /* * Remove the input queue from the looper it is currently attached to. diff --git a/native/include/android/looper.h b/native/include/android/looper.h index 90a8983..2917216 100644 --- a/native/include/android/looper.h +++ b/native/include/android/looper.h @@ -24,25 +24,151 @@ extern "C" { #endif +/** + * ALooper + * + * A looper is the state tracking an event loop for a thread. + * Loopers do not define event structures or other such things; rather + * they are a lower-level facility to attach one or more discrete objects + * listening for an event. An "event" here is simply data available on + * a file descriptor: each attached object has an associated file descriptor, + * and waiting for "events" means (internally) polling on all of these file + * descriptors until one or more of them have data available. + * + * A thread can have only one ALooper associated with it. + */ struct ALooper; typedef struct ALooper ALooper; +/** + * For callback-based event loops, this is the prototype of the function + * that is called. It is given the file descriptor it is associated with, + * a bitmask of the poll events that were triggered (typically POLLIN), and + * the data pointer that was originally supplied. + * + * Implementations should return 1 to continue receiving callbacks, or 0 + * to have this file descriptor and callback unregistered from the looper. + */ typedef int ALooper_callbackFunc(int fd, int events, void* data); +/** + * Return the ALooper associated with the calling thread, or NULL if + * there is not one. + */ ALooper* ALooper_forThread(); -ALooper* ALooper_prepare(); +enum { + /** + * Option for ALooper_prepare: this ALooper will accept calls to + * ALooper_addFd() that do not have a callback (that is provide NULL + * for the callback). In this case the caller of ALooper_pollOnce() + * or ALooper_pollAll() MUST check the return from these functions to + * discover when data is available on such fds and process it. + */ + ALOOPER_PREPARE_ALLOW_NON_CALLBACKS = 1<<0 +}; -int32_t ALooper_pollOnce(int timeoutMillis); +/** + * Prepare an ALooper associated with the calling thread, and return it. + * If the thread already has an ALooper, it is returned. Otherwise, a new + * one is created, associated with the thread, and returned. + * + * The opts may be ALOOPER_PREPARE_ALLOW_NON_CALLBACKS or 0. + */ +ALooper* ALooper_prepare(int32_t opts); + +enum { + /** + * Result from ALooper_pollOnce() and ALooper_pollAll(): one or + * more callbacks were executed. + */ + ALOOPER_POLL_CALLBACK = -1, + + /** + * Result from ALooper_pollOnce() and ALooper_pollAll(): the + * timeout expired. + */ + ALOOPER_POLL_TIMEOUT = -2, + + /** + * Result from ALooper_pollOnce() and ALooper_pollAll(): an error + * occurred. + */ + ALOOPER_POLL_ERROR = -3, +}; +/** + * Wait for events to be available, with optional timeout in milliseconds. + * Invokes callbacks for all file descriptors on which an event occurred. + * + * If the timeout is zero, returns immediately without blocking. + * If the timeout is negative, waits indefinitely until an event appears. + * + * Returns ALOOPER_POLL_CALLBACK if a callback was invoked. + * + * Returns ALOOPER_POLL_TIMEOUT if there was no data before the given + * timeout expired. + * + * Returns ALOPER_POLL_ERROR if an error occurred. + * + * Returns a value >= 0 containing a file descriptor if it 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. + * + * This method does not return until it has finished invoking the appropriate callbacks + * for all file descriptors that were signalled. + */ +int32_t ALooper_pollOnce(int timeoutMillis, int* outEvents, void** outData); + +/** + * Like ALooper_pollOnce(), but performs all pending callbacks until all + * data has been consumed or a file descriptor is available with no callback. + * This function will never return ALOOPER_POLL_CALLBACK. + */ +int32_t ALooper_pollAll(int timeoutMillis, int* outEvents, void** outData); + +/** + * Acquire a reference on the given ALooper object. This prevents the object + * from being deleted until the reference is removed. This is only needed + * to safely hand an ALooper from one thread to another. + */ void ALooper_acquire(ALooper* looper); +/** + * Remove a reference that was previously acquired with ALooper_acquire(). + */ void ALooper_release(ALooper* looper); -void ALooper_setCallback(ALooper* looper, int fd, int events, +/** + * Add a new file descriptor to be polled by the looper. If the same file + * descriptor was previously added, it is replaced. + * + * "fd" is the file descriptor to be added. + * "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: + * + * (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. + * + * (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. + */ +void ALooper_addFd(ALooper* looper, int fd, int events, ALooper_callbackFunc* callback, void* data); -int32_t ALooper_removeCallback(ALooper* looper, int fd); +/** + * Remove a previously added file descriptor from the looper. + */ +int32_t ALooper_removeFd(ALooper* looper, int fd); #ifdef __cplusplus }; diff --git a/native/include/android/native_activity.h b/native/include/android/native_activity.h index a31c5af..d0ff052 100644 --- a/native/include/android/native_activity.h +++ b/native/include/android/native_activity.h @@ -192,6 +192,11 @@ typedef void ANativeActivity_createFunc(ANativeActivity* activity, */ extern ANativeActivity_createFunc ANativeActivity_onCreate; +void ANativeActivity_setWindowFormat(ANativeActivity* activity, int32_t format); + +void ANativeActivity_setWindowFlags(ANativeActivity* activity, + uint32_t addFlags, uint32_t removeFlags); + #ifdef __cplusplus }; #endif diff --git a/native/include/android/native_window.h b/native/include/android/native_window.h index 678ba3d..7599d7e 100644 --- a/native/include/android/native_window.h +++ b/native/include/android/native_window.h @@ -14,10 +14,11 @@ * limitations under the License. */ - #ifndef ANDROID_NATIVE_WINDOW_H #define ANDROID_NATIVE_WINDOW_H +#include <android/rect.h> + #ifdef __cplusplus extern "C" { #endif @@ -34,6 +35,27 @@ enum { struct ANativeWindow; typedef struct ANativeWindow ANativeWindow; +typedef struct ANativeWindow_Buffer { + int32_t width; + int32_t height; + int32_t stride; + int32_t format; + void* bits; + + uint32_t reserved[6]; +} ANativeWindow_Buffer; + +/** + * Acquire a reference on the given ANativeWindow object. This prevents the object + * from being deleted until the reference is removed. + */ +void ANativeWindow_acquire(ANativeWindow* window); + +/** + * Remove a reference that was previously acquired with ANativeWindow_acquire(). + */ +void ANativeWindow_release(ANativeWindow* window); + /* * Return the current width in pixels of the window surface. Returns a * negative value on error. @@ -60,13 +82,22 @@ int32_t ANativeWindow_getFormat(ANativeWindow* window); * window's physical size, then it buffer will be scaled to match that size * when compositing it to the screen. * - * The format may be one of the window format constants above. - * - * For all of these parameters, if 0 is supplied than the window's base + * For all of these parameters, if 0 is supplied then the window's base * value will come back in force. */ -int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, - int32_t height, int32_t format); +int32_t ANativeWindow_setBuffersGeometry(ANativeWindow* window, int32_t width, int32_t height); + +/** + * Lock the window's next drawing surface for writing. + */ +int32_t ANativeWindow_lock(ANativeWindow* window, ANativeWindow_Buffer* outBuffer, + ARect* inOutDirtyBounds); + +/** + * Unlock the window's drawing surface after previously locking it, + * posting the new buffer to the display. + */ +int32_t ANativeWindow_unlockAndPost(ANativeWindow* window); #ifdef __cplusplus }; diff --git a/native/include/android/native_window_jni.h b/native/include/android/native_window_jni.h new file mode 100644 index 0000000..b9e72ef --- /dev/null +++ b/native/include/android/native_window_jni.h @@ -0,0 +1,40 @@ +/* + * 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_NATIVE_WINDOW_JNI_H +#define ANDROID_NATIVE_WINDOW_JNI_H + +#include <android/native_window.h> + +#include <jni.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Return the ANativeWindow associated with a Java Surface object, + * for interacting with it through native code. This acquires a reference + * on the ANativeWindow that is returned; be sure to use ANativeWindow_release() + * when done with it so that it doesn't leak. + */ +ANativeWindow* ANativeWindow_fromSurface(JNIEnv* env, jobject surface); + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_NATIVE_WINDOW_H diff --git a/native/include/android/rect.h b/native/include/android/rect.h new file mode 100644 index 0000000..3e81f53 --- /dev/null +++ b/native/include/android/rect.h @@ -0,0 +1,36 @@ +/* + * 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_RECT_H +#define ANDROID_RECT_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct ARect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} ARect; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_RECT_H diff --git a/native/include/android/window.h b/native/include/android/window.h new file mode 100644 index 0000000..2ab192b --- /dev/null +++ b/native/include/android/window.h @@ -0,0 +1,58 @@ +/* + * 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_WINDOW_H +#define ANDROID_WINDOW_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Window flags, as per the Java API at android.view.WindowManager.LayoutParams. + */ +enum { + AWINDOW_FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, + AWINDOW_FLAG_DIM_BEHIND = 0x00000002, + AWINDOW_FLAG_BLUR_BEHIND = 0x00000004, + AWINDOW_FLAG_NOT_FOCUSABLE = 0x00000008, + AWINDOW_FLAG_NOT_TOUCHABLE = 0x00000010, + AWINDOW_FLAG_NOT_TOUCH_MODAL = 0x00000020, + AWINDOW_FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, + AWINDOW_FLAG_KEEP_SCREEN_ON = 0x00000080, + AWINDOW_FLAG_LAYOUT_IN_SCREEN = 0x00000100, + AWINDOW_FLAG_LAYOUT_NO_LIMITS = 0x00000200, + AWINDOW_FLAG_FULLSCREEN = 0x00000400, + AWINDOW_FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, + AWINDOW_FLAG_DITHER = 0x00001000, + AWINDOW_FLAG_SECURE = 0x00002000, + AWINDOW_FLAG_SCALED = 0x00004000, + AWINDOW_FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, + AWINDOW_FLAG_LAYOUT_INSET_DECOR = 0x00010000, + AWINDOW_FLAG_ALT_FOCUSABLE_IM = 0x00020000, + AWINDOW_FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, + AWINDOW_FLAG_SHOW_WHEN_LOCKED = 0x00080000, + AWINDOW_FLAG_SHOW_WALLPAPER = 0x00100000, + AWINDOW_FLAG_TURN_SCREEN_ON = 0x00200000, + AWINDOW_FLAG_DISMISS_KEYGUARD = 0x00400000, +}; + +#ifdef __cplusplus +}; +#endif + +#endif // ANDROID_WINDOW_H diff --git a/native/include/android_glue/threaded_app.h b/native/include/android_glue/threaded_app.h new file mode 100644 index 0000000..adfdbea --- /dev/null +++ b/native/include/android_glue/threaded_app.h @@ -0,0 +1,165 @@ +/* + * 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. + * + */ + +#include <poll.h> +#include <pthread.h> +#include <sched.h> + +#include <android/native_activity.h> +#include <android/looper.h> + +/** + * This is the interface for the standard glue code of a threaded + * application. In this model, the application's code is running + * in its own thread separate from the main thread of the process. + * It is not required that this thread be associated with the Java + * VM, although it will need to be in order to make JNI calls any + * Java objects. + */ +struct android_app { + // The application can place a pointer to its own state object + // here if it likes. + void* userData; + + // The ANativeActivity object instance that this app is running in. + ANativeActivity* activity; + + // The ALooper associated with the app's thread. + ALooper* looper; + + // When non-NULL, this is the input queue from which the app will + // receive user input events. + AInputQueue* inputQueue; + + // When non-NULL, this is the window surface that the app can draw in. + ANativeWindow* window; + + // Current state of the app's activity. May be either APP_CMD_START, + // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. + int activityState; + + // ------------------------------------------------- + // Below are "private" implementation of the glue code. + + pthread_mutex_t mutex; + pthread_cond_t cond; + + int msgread; + int msgwrite; + + pthread_t thread; + + // This is non-zero when the application's NativeActivity is being + // destroyed and waiting for the app thread to complete. + int destroyRequested; + + int running; + int destroyed; + AInputQueue* pendingInputQueue; + ANativeWindow* pendingWindow; +}; + +enum { + /** + * Looper data ID of commands coming from the app's main thread. + * These can be retrieved and processed with android_app_read_cmd() + * and android_app_exec_cmd(). + */ + LOOPER_ID_MAIN = 1, + + /** + * Looper data ID of events coming from the AInputQueue of the + * application's window. These can be read via the inputQueue + * object of android_app. + */ + LOOPER_ID_EVENT = 2 +}; + +enum { + /** + * Command from main thread: the AInputQueue has changed. Upon processing + * this command, android_app->inputQueue will be updated to the new queue + * (or NULL). + */ + APP_CMD_INPUT_CHANGED, + + /** + * Command from main thread: the ANativeWindow has changed. Upon processing + * this command, android_app->window will be updated to the new window surface + * (or NULL). + */ + APP_CMD_WINDOW_CHANGED, + + /** + * Command from main thread: the app's activity window has gained + * input focus. + */ + APP_CMD_GAINED_FOCUS, + + /** + * Command from main thread: the app's activity window has lost + * input focus. + */ + APP_CMD_LOST_FOCUS, + + /** + * Command from main thread: the app's activity has been started. + */ + APP_CMD_START, + + /** + * Command from main thread: the app's activity has been resumed. + */ + APP_CMD_RESUME, + + /** + * Command from main thread: the app's activity has been paused. + */ + APP_CMD_PAUSE, + + /** + * Command from main thread: the app's activity has been stopped. + */ + APP_CMD_STOP, + + /** + * Command from main thread: the app's activity is being destroyed, + * and waiting for the app thread to clean up and exit before proceeding. + */ + APP_CMD_DESTROY, +}; + +/** + * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next + * app command message. + */ +int8_t android_app_read_cmd(struct android_app* android_app); + +/** + * Call with the command returned by android_app_read_cmd() to do the + * default processing of the given command. + * + * Important: returns 0 if the app should exit. You must ALWAYS check for + * a zero return and, if found, exit your android_main() function. + */ +int32_t android_app_exec_cmd(struct android_app* android_app, int8_t cmd); + +/** + * This is the function that application code must implement, representing + * the main entry to the app. + */ +extern void android_main(struct android_app* app); |