Update to use new looper API.
Also need to put back the stub Java class for now, as the build system still seems to require it. Change-Id: I31917a1fc7c0bf8cd928969125f94d55c59d42f8
This commit is contained in:
@@ -42,6 +42,7 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <android/keycodes.h>
|
||||
#include <android/looper.h>
|
||||
|
||||
#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
|
||||
|
||||
@@ -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 <poll.h>
|
||||
|
||||
#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
|
||||
@@ -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
|
||||
|
||||
Binary file not shown.
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "glutils.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const char *EGLstrerror(EGLint err) {
|
||||
switch (err) {
|
||||
case EGL_SUCCESS: return "EGL_SUCCESS";
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
4
ndk/samples/native-activity/src/Dummy.java
Normal file
4
ndk/samples/native-activity/src/Dummy.java
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
// Only needed for the build system.
|
||||
public class Dummy {
|
||||
}
|
||||
Reference in New Issue
Block a user