summaryrefslogtreecommitdiffstats
path: root/native/include
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2010-07-07 14:27:31 -0700
committerDianne Hackborn <hackbod@google.com>2010-07-08 11:06:59 -0700
commit85448bbecd4e0909eecfab15b7c3605f114d0427 (patch)
tree3380a9a85e321dc7ee4397dc1b4f22564af117d8 /native/include
parentf7d2b4a2e096ae1f8ac3a2ed8b2f0e30a237f732 (diff)
downloadframeworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.zip
frameworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.tar.gz
frameworks_base-85448bbecd4e0909eecfab15b7c3605f114d0427.tar.bz2
Add new glue code for writing native apps.
This factors out the boiler-plate code from the sample app to a common glue code that can be used for everyone writing this style of app: a dedicated app thread that takes care of waiting for events and processing them. As part of doing this, ALooper has a new facility to allow registration of fds that cause ALooper_pollOnce() to return the fd that has data, allowing the app to drive the loop without callbacks. Hopefully this makes some people feel better. :) Also do some other cleanup of the ALooper API, plus some actual documentation. Change-Id: Ic53bd56bdf627e3ba28a3c093faa06a92be522b8
Diffstat (limited to 'native/include')
-rw-r--r--native/include/android/input.h5
-rw-r--r--native/include/android/looper.h134
-rw-r--r--native/include/android_glue/threaded_app.h168
3 files changed, 301 insertions, 6 deletions
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_glue/threaded_app.h b/native/include/android_glue/threaded_app.h
new file mode 100644
index 0000000..80de3bf
--- /dev/null
+++ b/native/include/android_glue/threaded_app.h
@@ -0,0 +1,168 @@
+/*
+ * 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;
+
+ // This is non-zero when the application's NativeActivity is being
+ // destroyed and waiting for the app thread to complete.
+ int destroyRequested;
+
+ // -------------------------------------------------
+ // Below are "private" implementation of the glue code.
+
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+
+ int msgread;
+ int msgwrite;
+
+ pthread_t thread;
+
+ 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 if android_app->destroyRequested is non-zero. Upon return, the
+ * android_app structure is no longer valid and must not be touched.
+ */
+void android_app_destroy(struct android_app* android_app);
+
+/**
+ * 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.
+ */
+void 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);