ndktest
changeset 0:1310df7cdf25
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 23 Apr 2015 20:54:02 +0300 |
parents | |
children | fe78cf853157 |
files | .hgignore AndroidManifest.xml Makefile README src/android_native_app_glue.c src/android_native_app_glue.h src/app.c src/app.h src/logger.c src/logger.h src/main.c |
diffstat | 11 files changed, 1310 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/.hgignore Thu Apr 23 20:54:02 2015 +0300 1.3 @@ -0,0 +1,10 @@ 1.4 +\.o$ 1.5 +\.swp$ 1.6 +\.d$ 1.7 +^bin/ 1.8 +^libs/ 1.9 +^res/ 1.10 +^build.xml$ 1.11 +\.properties$ 1.12 +\.java$ 1.13 +proguard-project\.txt$
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/AndroidManifest.xml Thu Apr 23 20:54:02 2015 +0300 2.3 @@ -0,0 +1,25 @@ 2.4 +<?xml version="1.0" encoding="utf-8"?> 2.5 +<manifest xmlns:android="http://schemas.android.com/apk/res/android" 2.6 + package="com.mutantstargoat.ndktest" 2.7 + android:versionCode="1" 2.8 + android:versionName="1.0"> 2.9 + 2.10 + <uses-sdk android:minSdkVersion="9"/> 2.11 + 2.12 + <application android:label="@string/app_name" 2.13 + android:hasCode="false" 2.14 + android:debuggable="true" 2.15 + android:icon="@drawable/ic_launcher"> 2.16 + 2.17 + <activity android:name="android.app.NativeActivity" 2.18 + android:label="@string/app_name"> 2.19 + 2.20 + <meta-data android:name="android.app.lib_name" android:value="ndktest"/> 2.21 + 2.22 + <intent-filter> 2.23 + <action android:name="android.intent.action.MAIN" /> 2.24 + <category android:name="android.intent.category.LAUNCHER" /> 2.25 + </intent-filter> 2.26 + </activity> 2.27 + </application> 2.28 +</manifest>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/Makefile Thu Apr 23 20:54:02 2015 +0300 3.3 @@ -0,0 +1,62 @@ 3.4 +android_platform = android-21 3.5 + 3.6 +src = $(wildcard src/*.c) 3.7 +obj = $(src:.c=.o) 3.8 +name = ndktest 3.9 +lib = libs/armeabi/lib$(name).so 3.10 +apk-release = bin/$(name).apk 3.11 +apk-debug = bin/$(name)-debug.apk 3.12 + 3.13 +pkg = com.mutantstargoat.ndktest 3.14 +act = android.app.NativeActivity 3.15 + 3.16 +CC = arm-linux-androideabi-gcc 3.17 + 3.18 +android_usr = $(NDK)/platforms/$(android_platform)/arch-arm/usr 3.19 +android_inc = -I$(android_usr)/include 3.20 +android_libs = -L$(android_usr)/lib -llog -landroid -lEGL -lGLESv1_CM 3.21 + 3.22 +CFLAGS = -std=c99 -pedantic -Wall -g $(android_inc) -Isrc 3.23 +LDFLAGS = -Wl,--fix-cortex-a8 $(android_libs) 3.24 + 3.25 +.PHONY: debug 3.26 +debug: $(apk-debug) 3.27 + 3.28 +.PHONY: release 3.29 +release: $(apk-release) 3.30 + 3.31 +$(apk-debug): $(lib) 3.32 + ant debug 3.33 + 3.34 +$(apk-release): $(lib) 3.35 + ant release 3.36 + 3.37 +.PHONY: lib 3.38 +lib: $(lib) 3.39 + 3.40 +$(lib): $(obj) 3.41 + @mkdir -p libs/armeabi 3.42 + $(CC) -o $@ -shared $(obj) $(LDFLAGS) 3.43 + 3.44 +.PHONY: clean 3.45 +clean: 3.46 + rm -f $(obj) $(lib) $(apk-release) $(apk-debug) 3.47 + 3.48 +.PHONY: install 3.49 +install: install-debug 3.50 + 3.51 +.PHONY: install-debug 3.52 +install-debug: 3.53 + adb install -r $(apk-debug) 3.54 + 3.55 +.PHONY: install-release 3.56 +install-release: 3.57 + adb install -r $(apk-release) 3.58 + 3.59 +.PHONY: run 3.60 +run: 3.61 + adb shell am start -n $(pkg)/$(act) 3.62 + 3.63 +.PHONY: stop 3.64 +stop: 3.65 + adb shell am force-stop $(pkg)
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/README Thu Apr 23 20:54:02 2015 +0300 4.3 @@ -0,0 +1,14 @@ 4.4 +Setup instructions 4.5 +------------------ 4.6 +$NDK/build/tools/make-standalone-toolchain.sh \ 4.7 + --platform=android-21 --arch=arm \ 4.8 + --install-dir=$HOME/devel/ndk-toolchain 4.9 + 4.10 +export PATH=$HOME/devel/ndk-toolchain/bin 4.11 +export CC=arm-linux-androideabi-gcc 4.12 + 4.13 + * use -mthumb (so says the doc) 4.14 + * use LDFLAGS -Wl,--fix-cortex-a8 4.15 + * use LDFLAGS -lstdc++ to statically link the GNU C++ library 4.16 + * for armeabi-v7a ABI: -march=armv7-a -mfloat-abi=softfp 4.17 + * for neon: -march=arm7-a -mfloat-abi=softfp -mfpu=neon
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/android_native_app_glue.c Thu Apr 23 20:54:02 2015 +0300 5.3 @@ -0,0 +1,440 @@ 5.4 +/* 5.5 + * Copyright (C) 2010 The Android Open Source Project 5.6 + * 5.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 5.8 + * you may not use this file except in compliance with the License. 5.9 + * You may obtain a copy of the License at 5.10 + * 5.11 + * http://www.apache.org/licenses/LICENSE-2.0 5.12 + * 5.13 + * Unless required by applicable law or agreed to in writing, software 5.14 + * distributed under the License is distributed on an "AS IS" BASIS, 5.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 5.16 + * See the License for the specific language governing permissions and 5.17 + * limitations under the License. 5.18 + * 5.19 + */ 5.20 + 5.21 +#include <jni.h> 5.22 + 5.23 +#include <errno.h> 5.24 +#include <string.h> 5.25 +#include <unistd.h> 5.26 +#include <sys/resource.h> 5.27 + 5.28 +#include "android_native_app_glue.h" 5.29 +#include <android/log.h> 5.30 + 5.31 +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) 5.32 +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) 5.33 + 5.34 +/* For debug builds, always enable the debug traces in this library */ 5.35 +#ifndef NDEBUG 5.36 +# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) 5.37 +#else 5.38 +# define LOGV(...) ((void)0) 5.39 +#endif 5.40 + 5.41 +static void free_saved_state(struct android_app* android_app) { 5.42 + pthread_mutex_lock(&android_app->mutex); 5.43 + if (android_app->savedState != NULL) { 5.44 + free(android_app->savedState); 5.45 + android_app->savedState = NULL; 5.46 + android_app->savedStateSize = 0; 5.47 + } 5.48 + pthread_mutex_unlock(&android_app->mutex); 5.49 +} 5.50 + 5.51 +int8_t android_app_read_cmd(struct android_app* android_app) { 5.52 + int8_t cmd; 5.53 + if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { 5.54 + switch (cmd) { 5.55 + case APP_CMD_SAVE_STATE: 5.56 + free_saved_state(android_app); 5.57 + break; 5.58 + } 5.59 + return cmd; 5.60 + } else { 5.61 + LOGE("No data on command pipe!"); 5.62 + } 5.63 + return -1; 5.64 +} 5.65 + 5.66 +static void print_cur_config(struct android_app* android_app) { 5.67 + char lang[2], country[2]; 5.68 + AConfiguration_getLanguage(android_app->config, lang); 5.69 + AConfiguration_getCountry(android_app->config, country); 5.70 + 5.71 + LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " 5.72 + "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " 5.73 + "modetype=%d modenight=%d", 5.74 + AConfiguration_getMcc(android_app->config), 5.75 + AConfiguration_getMnc(android_app->config), 5.76 + lang[0], lang[1], country[0], country[1], 5.77 + AConfiguration_getOrientation(android_app->config), 5.78 + AConfiguration_getTouchscreen(android_app->config), 5.79 + AConfiguration_getDensity(android_app->config), 5.80 + AConfiguration_getKeyboard(android_app->config), 5.81 + AConfiguration_getNavigation(android_app->config), 5.82 + AConfiguration_getKeysHidden(android_app->config), 5.83 + AConfiguration_getNavHidden(android_app->config), 5.84 + AConfiguration_getSdkVersion(android_app->config), 5.85 + AConfiguration_getScreenSize(android_app->config), 5.86 + AConfiguration_getScreenLong(android_app->config), 5.87 + AConfiguration_getUiModeType(android_app->config), 5.88 + AConfiguration_getUiModeNight(android_app->config)); 5.89 +} 5.90 + 5.91 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { 5.92 + switch (cmd) { 5.93 + case APP_CMD_INPUT_CHANGED: 5.94 + LOGV("APP_CMD_INPUT_CHANGED\n"); 5.95 + pthread_mutex_lock(&android_app->mutex); 5.96 + if (android_app->inputQueue != NULL) { 5.97 + AInputQueue_detachLooper(android_app->inputQueue); 5.98 + } 5.99 + android_app->inputQueue = android_app->pendingInputQueue; 5.100 + if (android_app->inputQueue != NULL) { 5.101 + LOGV("Attaching input queue to looper"); 5.102 + AInputQueue_attachLooper(android_app->inputQueue, 5.103 + android_app->looper, LOOPER_ID_INPUT, NULL, 5.104 + &android_app->inputPollSource); 5.105 + } 5.106 + pthread_cond_broadcast(&android_app->cond); 5.107 + pthread_mutex_unlock(&android_app->mutex); 5.108 + break; 5.109 + 5.110 + case APP_CMD_INIT_WINDOW: 5.111 + LOGV("APP_CMD_INIT_WINDOW\n"); 5.112 + pthread_mutex_lock(&android_app->mutex); 5.113 + android_app->window = android_app->pendingWindow; 5.114 + pthread_cond_broadcast(&android_app->cond); 5.115 + pthread_mutex_unlock(&android_app->mutex); 5.116 + break; 5.117 + 5.118 + case APP_CMD_TERM_WINDOW: 5.119 + LOGV("APP_CMD_TERM_WINDOW\n"); 5.120 + pthread_cond_broadcast(&android_app->cond); 5.121 + break; 5.122 + 5.123 + case APP_CMD_RESUME: 5.124 + case APP_CMD_START: 5.125 + case APP_CMD_PAUSE: 5.126 + case APP_CMD_STOP: 5.127 + LOGV("activityState=%d\n", cmd); 5.128 + pthread_mutex_lock(&android_app->mutex); 5.129 + android_app->activityState = cmd; 5.130 + pthread_cond_broadcast(&android_app->cond); 5.131 + pthread_mutex_unlock(&android_app->mutex); 5.132 + break; 5.133 + 5.134 + case APP_CMD_CONFIG_CHANGED: 5.135 + LOGV("APP_CMD_CONFIG_CHANGED\n"); 5.136 + AConfiguration_fromAssetManager(android_app->config, 5.137 + android_app->activity->assetManager); 5.138 + print_cur_config(android_app); 5.139 + break; 5.140 + 5.141 + case APP_CMD_DESTROY: 5.142 + LOGV("APP_CMD_DESTROY\n"); 5.143 + android_app->destroyRequested = 1; 5.144 + break; 5.145 + } 5.146 +} 5.147 + 5.148 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { 5.149 + switch (cmd) { 5.150 + case APP_CMD_TERM_WINDOW: 5.151 + LOGV("APP_CMD_TERM_WINDOW\n"); 5.152 + pthread_mutex_lock(&android_app->mutex); 5.153 + android_app->window = NULL; 5.154 + pthread_cond_broadcast(&android_app->cond); 5.155 + pthread_mutex_unlock(&android_app->mutex); 5.156 + break; 5.157 + 5.158 + case APP_CMD_SAVE_STATE: 5.159 + LOGV("APP_CMD_SAVE_STATE\n"); 5.160 + pthread_mutex_lock(&android_app->mutex); 5.161 + android_app->stateSaved = 1; 5.162 + pthread_cond_broadcast(&android_app->cond); 5.163 + pthread_mutex_unlock(&android_app->mutex); 5.164 + break; 5.165 + 5.166 + case APP_CMD_RESUME: 5.167 + free_saved_state(android_app); 5.168 + break; 5.169 + } 5.170 +} 5.171 + 5.172 +void app_dummy() { 5.173 + 5.174 +} 5.175 + 5.176 +static void android_app_destroy(struct android_app* android_app) { 5.177 + LOGV("android_app_destroy!"); 5.178 + free_saved_state(android_app); 5.179 + pthread_mutex_lock(&android_app->mutex); 5.180 + if (android_app->inputQueue != NULL) { 5.181 + AInputQueue_detachLooper(android_app->inputQueue); 5.182 + } 5.183 + AConfiguration_delete(android_app->config); 5.184 + android_app->destroyed = 1; 5.185 + pthread_cond_broadcast(&android_app->cond); 5.186 + pthread_mutex_unlock(&android_app->mutex); 5.187 + // Can't touch android_app object after this. 5.188 +} 5.189 + 5.190 +static void process_input(struct android_app* app, struct android_poll_source* source) { 5.191 + AInputEvent* event = NULL; 5.192 + while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { 5.193 + LOGV("New input event: type=%d\n", AInputEvent_getType(event)); 5.194 + if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { 5.195 + continue; 5.196 + } 5.197 + int32_t handled = 0; 5.198 + if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); 5.199 + AInputQueue_finishEvent(app->inputQueue, event, handled); 5.200 + } 5.201 +} 5.202 + 5.203 +static void process_cmd(struct android_app* app, struct android_poll_source* source) { 5.204 + int8_t cmd = android_app_read_cmd(app); 5.205 + android_app_pre_exec_cmd(app, cmd); 5.206 + if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); 5.207 + android_app_post_exec_cmd(app, cmd); 5.208 +} 5.209 + 5.210 +static void* android_app_entry(void* param) { 5.211 + struct android_app* android_app = (struct android_app*)param; 5.212 + 5.213 + android_app->config = AConfiguration_new(); 5.214 + AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); 5.215 + 5.216 + print_cur_config(android_app); 5.217 + 5.218 + android_app->cmdPollSource.id = LOOPER_ID_MAIN; 5.219 + android_app->cmdPollSource.app = android_app; 5.220 + android_app->cmdPollSource.process = process_cmd; 5.221 + android_app->inputPollSource.id = LOOPER_ID_INPUT; 5.222 + android_app->inputPollSource.app = android_app; 5.223 + android_app->inputPollSource.process = process_input; 5.224 + 5.225 + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); 5.226 + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, 5.227 + &android_app->cmdPollSource); 5.228 + android_app->looper = looper; 5.229 + 5.230 + pthread_mutex_lock(&android_app->mutex); 5.231 + android_app->running = 1; 5.232 + pthread_cond_broadcast(&android_app->cond); 5.233 + pthread_mutex_unlock(&android_app->mutex); 5.234 + 5.235 + android_main(android_app); 5.236 + 5.237 + android_app_destroy(android_app); 5.238 + return NULL; 5.239 +} 5.240 + 5.241 +// -------------------------------------------------------------------- 5.242 +// Native activity interaction (called from main thread) 5.243 +// -------------------------------------------------------------------- 5.244 + 5.245 +static struct android_app* android_app_create(ANativeActivity* activity, 5.246 + void* savedState, size_t savedStateSize) { 5.247 + struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); 5.248 + memset(android_app, 0, sizeof(struct android_app)); 5.249 + android_app->activity = activity; 5.250 + 5.251 + pthread_mutex_init(&android_app->mutex, NULL); 5.252 + pthread_cond_init(&android_app->cond, NULL); 5.253 + 5.254 + if (savedState != NULL) { 5.255 + android_app->savedState = malloc(savedStateSize); 5.256 + android_app->savedStateSize = savedStateSize; 5.257 + memcpy(android_app->savedState, savedState, savedStateSize); 5.258 + } 5.259 + 5.260 + int msgpipe[2]; 5.261 + if (pipe(msgpipe)) { 5.262 + LOGE("could not create pipe: %s", strerror(errno)); 5.263 + return NULL; 5.264 + } 5.265 + android_app->msgread = msgpipe[0]; 5.266 + android_app->msgwrite = msgpipe[1]; 5.267 + 5.268 + pthread_attr_t attr; 5.269 + pthread_attr_init(&attr); 5.270 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 5.271 + pthread_create(&android_app->thread, &attr, android_app_entry, android_app); 5.272 + 5.273 + // Wait for thread to start. 5.274 + pthread_mutex_lock(&android_app->mutex); 5.275 + while (!android_app->running) { 5.276 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.277 + } 5.278 + pthread_mutex_unlock(&android_app->mutex); 5.279 + 5.280 + return android_app; 5.281 +} 5.282 + 5.283 +static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { 5.284 + if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { 5.285 + LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); 5.286 + } 5.287 +} 5.288 + 5.289 +static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { 5.290 + pthread_mutex_lock(&android_app->mutex); 5.291 + android_app->pendingInputQueue = inputQueue; 5.292 + android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); 5.293 + while (android_app->inputQueue != android_app->pendingInputQueue) { 5.294 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.295 + } 5.296 + pthread_mutex_unlock(&android_app->mutex); 5.297 +} 5.298 + 5.299 +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { 5.300 + pthread_mutex_lock(&android_app->mutex); 5.301 + if (android_app->pendingWindow != NULL) { 5.302 + android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); 5.303 + } 5.304 + android_app->pendingWindow = window; 5.305 + if (window != NULL) { 5.306 + android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); 5.307 + } 5.308 + while (android_app->window != android_app->pendingWindow) { 5.309 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.310 + } 5.311 + pthread_mutex_unlock(&android_app->mutex); 5.312 +} 5.313 + 5.314 +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { 5.315 + pthread_mutex_lock(&android_app->mutex); 5.316 + android_app_write_cmd(android_app, cmd); 5.317 + while (android_app->activityState != cmd) { 5.318 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.319 + } 5.320 + pthread_mutex_unlock(&android_app->mutex); 5.321 +} 5.322 + 5.323 +static void android_app_free(struct android_app* android_app) { 5.324 + pthread_mutex_lock(&android_app->mutex); 5.325 + android_app_write_cmd(android_app, APP_CMD_DESTROY); 5.326 + while (!android_app->destroyed) { 5.327 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.328 + } 5.329 + pthread_mutex_unlock(&android_app->mutex); 5.330 + 5.331 + close(android_app->msgread); 5.332 + close(android_app->msgwrite); 5.333 + pthread_cond_destroy(&android_app->cond); 5.334 + pthread_mutex_destroy(&android_app->mutex); 5.335 + free(android_app); 5.336 +} 5.337 + 5.338 +static void onDestroy(ANativeActivity* activity) { 5.339 + LOGV("Destroy: %p\n", activity); 5.340 + android_app_free((struct android_app*)activity->instance); 5.341 +} 5.342 + 5.343 +static void onStart(ANativeActivity* activity) { 5.344 + LOGV("Start: %p\n", activity); 5.345 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); 5.346 +} 5.347 + 5.348 +static void onResume(ANativeActivity* activity) { 5.349 + LOGV("Resume: %p\n", activity); 5.350 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); 5.351 +} 5.352 + 5.353 +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { 5.354 + struct android_app* android_app = (struct android_app*)activity->instance; 5.355 + void* savedState = NULL; 5.356 + 5.357 + LOGV("SaveInstanceState: %p\n", activity); 5.358 + pthread_mutex_lock(&android_app->mutex); 5.359 + android_app->stateSaved = 0; 5.360 + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); 5.361 + while (!android_app->stateSaved) { 5.362 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 5.363 + } 5.364 + 5.365 + if (android_app->savedState != NULL) { 5.366 + savedState = android_app->savedState; 5.367 + *outLen = android_app->savedStateSize; 5.368 + android_app->savedState = NULL; 5.369 + android_app->savedStateSize = 0; 5.370 + } 5.371 + 5.372 + pthread_mutex_unlock(&android_app->mutex); 5.373 + 5.374 + return savedState; 5.375 +} 5.376 + 5.377 +static void onPause(ANativeActivity* activity) { 5.378 + LOGV("Pause: %p\n", activity); 5.379 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); 5.380 +} 5.381 + 5.382 +static void onStop(ANativeActivity* activity) { 5.383 + LOGV("Stop: %p\n", activity); 5.384 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); 5.385 +} 5.386 + 5.387 +static void onConfigurationChanged(ANativeActivity* activity) { 5.388 + struct android_app* android_app = (struct android_app*)activity->instance; 5.389 + LOGV("ConfigurationChanged: %p\n", activity); 5.390 + android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); 5.391 +} 5.392 + 5.393 +static void onLowMemory(ANativeActivity* activity) { 5.394 + struct android_app* android_app = (struct android_app*)activity->instance; 5.395 + LOGV("LowMemory: %p\n", activity); 5.396 + android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); 5.397 +} 5.398 + 5.399 +static void onWindowFocusChanged(ANativeActivity* activity, int focused) { 5.400 + LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); 5.401 + android_app_write_cmd((struct android_app*)activity->instance, 5.402 + focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); 5.403 +} 5.404 + 5.405 +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { 5.406 + LOGV("NativeWindowCreated: %p -- %p\n", activity, window); 5.407 + android_app_set_window((struct android_app*)activity->instance, window); 5.408 +} 5.409 + 5.410 +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { 5.411 + LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); 5.412 + android_app_set_window((struct android_app*)activity->instance, NULL); 5.413 +} 5.414 + 5.415 +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { 5.416 + LOGV("InputQueueCreated: %p -- %p\n", activity, queue); 5.417 + android_app_set_input((struct android_app*)activity->instance, queue); 5.418 +} 5.419 + 5.420 +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { 5.421 + LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); 5.422 + android_app_set_input((struct android_app*)activity->instance, NULL); 5.423 +} 5.424 + 5.425 +void ANativeActivity_onCreate(ANativeActivity* activity, 5.426 + void* savedState, size_t savedStateSize) { 5.427 + LOGV("Creating: %p\n", activity); 5.428 + activity->callbacks->onDestroy = onDestroy; 5.429 + activity->callbacks->onStart = onStart; 5.430 + activity->callbacks->onResume = onResume; 5.431 + activity->callbacks->onSaveInstanceState = onSaveInstanceState; 5.432 + activity->callbacks->onPause = onPause; 5.433 + activity->callbacks->onStop = onStop; 5.434 + activity->callbacks->onConfigurationChanged = onConfigurationChanged; 5.435 + activity->callbacks->onLowMemory = onLowMemory; 5.436 + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; 5.437 + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; 5.438 + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; 5.439 + activity->callbacks->onInputQueueCreated = onInputQueueCreated; 5.440 + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; 5.441 + 5.442 + activity->instance = android_app_create(activity, savedState, savedStateSize); 5.443 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/src/android_native_app_glue.h Thu Apr 23 20:54:02 2015 +0300 6.3 @@ -0,0 +1,349 @@ 6.4 +/* 6.5 + * Copyright (C) 2010 The Android Open Source Project 6.6 + * 6.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 6.8 + * you may not use this file except in compliance with the License. 6.9 + * You may obtain a copy of the License at 6.10 + * 6.11 + * http://www.apache.org/licenses/LICENSE-2.0 6.12 + * 6.13 + * Unless required by applicable law or agreed to in writing, software 6.14 + * distributed under the License is distributed on an "AS IS" BASIS, 6.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 6.16 + * See the License for the specific language governing permissions and 6.17 + * limitations under the License. 6.18 + * 6.19 + */ 6.20 + 6.21 +#ifndef _ANDROID_NATIVE_APP_GLUE_H 6.22 +#define _ANDROID_NATIVE_APP_GLUE_H 6.23 + 6.24 +#include <poll.h> 6.25 +#include <pthread.h> 6.26 +#include <sched.h> 6.27 + 6.28 +#include <android/configuration.h> 6.29 +#include <android/looper.h> 6.30 +#include <android/native_activity.h> 6.31 + 6.32 +#ifdef __cplusplus 6.33 +extern "C" { 6.34 +#endif 6.35 + 6.36 +/** 6.37 + * The native activity interface provided by <android/native_activity.h> 6.38 + * is based on a set of application-provided callbacks that will be called 6.39 + * by the Activity's main thread when certain events occur. 6.40 + * 6.41 + * This means that each one of this callbacks _should_ _not_ block, or they 6.42 + * risk having the system force-close the application. This programming 6.43 + * model is direct, lightweight, but constraining. 6.44 + * 6.45 + * The 'android_native_app_glue' static library is used to provide a different 6.46 + * execution model where the application can implement its own main event 6.47 + * loop in a different thread instead. Here's how it works: 6.48 + * 6.49 + * 1/ The application must provide a function named "android_main()" that 6.50 + * will be called when the activity is created, in a new thread that is 6.51 + * distinct from the activity's main thread. 6.52 + * 6.53 + * 2/ android_main() receives a pointer to a valid "android_app" structure 6.54 + * that contains references to other important objects, e.g. the 6.55 + * ANativeActivity obejct instance the application is running in. 6.56 + * 6.57 + * 3/ the "android_app" object holds an ALooper instance that already 6.58 + * listens to two important things: 6.59 + * 6.60 + * - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX 6.61 + * declarations below. 6.62 + * 6.63 + * - input events coming from the AInputQueue attached to the activity. 6.64 + * 6.65 + * Each of these correspond to an ALooper identifier returned by 6.66 + * ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT, 6.67 + * respectively. 6.68 + * 6.69 + * Your application can use the same ALooper to listen to additional 6.70 + * file-descriptors. They can either be callback based, or with return 6.71 + * identifiers starting with LOOPER_ID_USER. 6.72 + * 6.73 + * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event, 6.74 + * the returned data will point to an android_poll_source structure. You 6.75 + * can call the process() function on it, and fill in android_app->onAppCmd 6.76 + * and android_app->onInputEvent to be called for your own processing 6.77 + * of the event. 6.78 + * 6.79 + * Alternatively, you can call the low-level functions to read and process 6.80 + * the data directly... look at the process_cmd() and process_input() 6.81 + * implementations in the glue to see how to do this. 6.82 + * 6.83 + * See the sample named "native-activity" that comes with the NDK with a 6.84 + * full usage example. Also look at the JavaDoc of NativeActivity. 6.85 + */ 6.86 + 6.87 +struct android_app; 6.88 + 6.89 +/** 6.90 + * Data associated with an ALooper fd that will be returned as the "outData" 6.91 + * when that source has data ready. 6.92 + */ 6.93 +struct android_poll_source { 6.94 + // The identifier of this source. May be LOOPER_ID_MAIN or 6.95 + // LOOPER_ID_INPUT. 6.96 + int32_t id; 6.97 + 6.98 + // The android_app this ident is associated with. 6.99 + struct android_app* app; 6.100 + 6.101 + // Function to call to perform the standard processing of data from 6.102 + // this source. 6.103 + void (*process)(struct android_app* app, struct android_poll_source* source); 6.104 +}; 6.105 + 6.106 +/** 6.107 + * This is the interface for the standard glue code of a threaded 6.108 + * application. In this model, the application's code is running 6.109 + * in its own thread separate from the main thread of the process. 6.110 + * It is not required that this thread be associated with the Java 6.111 + * VM, although it will need to be in order to make JNI calls any 6.112 + * Java objects. 6.113 + */ 6.114 +struct android_app { 6.115 + // The application can place a pointer to its own state object 6.116 + // here if it likes. 6.117 + void* userData; 6.118 + 6.119 + // Fill this in with the function to process main app commands (APP_CMD_*) 6.120 + void (*onAppCmd)(struct android_app* app, int32_t cmd); 6.121 + 6.122 + // Fill this in with the function to process input events. At this point 6.123 + // the event has already been pre-dispatched, and it will be finished upon 6.124 + // return. Return 1 if you have handled the event, 0 for any default 6.125 + // dispatching. 6.126 + int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); 6.127 + 6.128 + // The ANativeActivity object instance that this app is running in. 6.129 + ANativeActivity* activity; 6.130 + 6.131 + // The current configuration the app is running in. 6.132 + AConfiguration* config; 6.133 + 6.134 + // This is the last instance's saved state, as provided at creation time. 6.135 + // It is NULL if there was no state. You can use this as you need; the 6.136 + // memory will remain around until you call android_app_exec_cmd() for 6.137 + // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL. 6.138 + // These variables should only be changed when processing a APP_CMD_SAVE_STATE, 6.139 + // at which point they will be initialized to NULL and you can malloc your 6.140 + // state and place the information here. In that case the memory will be 6.141 + // freed for you later. 6.142 + void* savedState; 6.143 + size_t savedStateSize; 6.144 + 6.145 + // The ALooper associated with the app's thread. 6.146 + ALooper* looper; 6.147 + 6.148 + // When non-NULL, this is the input queue from which the app will 6.149 + // receive user input events. 6.150 + AInputQueue* inputQueue; 6.151 + 6.152 + // When non-NULL, this is the window surface that the app can draw in. 6.153 + ANativeWindow* window; 6.154 + 6.155 + // Current content rectangle of the window; this is the area where the 6.156 + // window's content should be placed to be seen by the user. 6.157 + ARect contentRect; 6.158 + 6.159 + // Current state of the app's activity. May be either APP_CMD_START, 6.160 + // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below. 6.161 + int activityState; 6.162 + 6.163 + // This is non-zero when the application's NativeActivity is being 6.164 + // destroyed and waiting for the app thread to complete. 6.165 + int destroyRequested; 6.166 + 6.167 + // ------------------------------------------------- 6.168 + // Below are "private" implementation of the glue code. 6.169 + 6.170 + pthread_mutex_t mutex; 6.171 + pthread_cond_t cond; 6.172 + 6.173 + int msgread; 6.174 + int msgwrite; 6.175 + 6.176 + pthread_t thread; 6.177 + 6.178 + struct android_poll_source cmdPollSource; 6.179 + struct android_poll_source inputPollSource; 6.180 + 6.181 + int running; 6.182 + int stateSaved; 6.183 + int destroyed; 6.184 + int redrawNeeded; 6.185 + AInputQueue* pendingInputQueue; 6.186 + ANativeWindow* pendingWindow; 6.187 + ARect pendingContentRect; 6.188 +}; 6.189 + 6.190 +enum { 6.191 + /** 6.192 + * Looper data ID of commands coming from the app's main thread, which 6.193 + * is returned as an identifier from ALooper_pollOnce(). The data for this 6.194 + * identifier is a pointer to an android_poll_source structure. 6.195 + * These can be retrieved and processed with android_app_read_cmd() 6.196 + * and android_app_exec_cmd(). 6.197 + */ 6.198 + LOOPER_ID_MAIN = 1, 6.199 + 6.200 + /** 6.201 + * Looper data ID of events coming from the AInputQueue of the 6.202 + * application's window, which is returned as an identifier from 6.203 + * ALooper_pollOnce(). The data for this identifier is a pointer to an 6.204 + * android_poll_source structure. These can be read via the inputQueue 6.205 + * object of android_app. 6.206 + */ 6.207 + LOOPER_ID_INPUT = 2, 6.208 + 6.209 + /** 6.210 + * Start of user-defined ALooper identifiers. 6.211 + */ 6.212 + LOOPER_ID_USER = 3, 6.213 +}; 6.214 + 6.215 +enum { 6.216 + /** 6.217 + * Command from main thread: the AInputQueue has changed. Upon processing 6.218 + * this command, android_app->inputQueue will be updated to the new queue 6.219 + * (or NULL). 6.220 + */ 6.221 + APP_CMD_INPUT_CHANGED, 6.222 + 6.223 + /** 6.224 + * Command from main thread: a new ANativeWindow is ready for use. Upon 6.225 + * receiving this command, android_app->window will contain the new window 6.226 + * surface. 6.227 + */ 6.228 + APP_CMD_INIT_WINDOW, 6.229 + 6.230 + /** 6.231 + * Command from main thread: the existing ANativeWindow needs to be 6.232 + * terminated. Upon receiving this command, android_app->window still 6.233 + * contains the existing window; after calling android_app_exec_cmd 6.234 + * it will be set to NULL. 6.235 + */ 6.236 + APP_CMD_TERM_WINDOW, 6.237 + 6.238 + /** 6.239 + * Command from main thread: the current ANativeWindow has been resized. 6.240 + * Please redraw with its new size. 6.241 + */ 6.242 + APP_CMD_WINDOW_RESIZED, 6.243 + 6.244 + /** 6.245 + * Command from main thread: the system needs that the current ANativeWindow 6.246 + * be redrawn. You should redraw the window before handing this to 6.247 + * android_app_exec_cmd() in order to avoid transient drawing glitches. 6.248 + */ 6.249 + APP_CMD_WINDOW_REDRAW_NEEDED, 6.250 + 6.251 + /** 6.252 + * Command from main thread: the content area of the window has changed, 6.253 + * such as from the soft input window being shown or hidden. You can 6.254 + * find the new content rect in android_app::contentRect. 6.255 + */ 6.256 + APP_CMD_CONTENT_RECT_CHANGED, 6.257 + 6.258 + /** 6.259 + * Command from main thread: the app's activity window has gained 6.260 + * input focus. 6.261 + */ 6.262 + APP_CMD_GAINED_FOCUS, 6.263 + 6.264 + /** 6.265 + * Command from main thread: the app's activity window has lost 6.266 + * input focus. 6.267 + */ 6.268 + APP_CMD_LOST_FOCUS, 6.269 + 6.270 + /** 6.271 + * Command from main thread: the current device configuration has changed. 6.272 + */ 6.273 + APP_CMD_CONFIG_CHANGED, 6.274 + 6.275 + /** 6.276 + * Command from main thread: the system is running low on memory. 6.277 + * Try to reduce your memory use. 6.278 + */ 6.279 + APP_CMD_LOW_MEMORY, 6.280 + 6.281 + /** 6.282 + * Command from main thread: the app's activity has been started. 6.283 + */ 6.284 + APP_CMD_START, 6.285 + 6.286 + /** 6.287 + * Command from main thread: the app's activity has been resumed. 6.288 + */ 6.289 + APP_CMD_RESUME, 6.290 + 6.291 + /** 6.292 + * Command from main thread: the app should generate a new saved state 6.293 + * for itself, to restore from later if needed. If you have saved state, 6.294 + * allocate it with malloc and place it in android_app.savedState with 6.295 + * the size in android_app.savedStateSize. The will be freed for you 6.296 + * later. 6.297 + */ 6.298 + APP_CMD_SAVE_STATE, 6.299 + 6.300 + /** 6.301 + * Command from main thread: the app's activity has been paused. 6.302 + */ 6.303 + APP_CMD_PAUSE, 6.304 + 6.305 + /** 6.306 + * Command from main thread: the app's activity has been stopped. 6.307 + */ 6.308 + APP_CMD_STOP, 6.309 + 6.310 + /** 6.311 + * Command from main thread: the app's activity is being destroyed, 6.312 + * and waiting for the app thread to clean up and exit before proceeding. 6.313 + */ 6.314 + APP_CMD_DESTROY, 6.315 +}; 6.316 + 6.317 +/** 6.318 + * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next 6.319 + * app command message. 6.320 + */ 6.321 +int8_t android_app_read_cmd(struct android_app* android_app); 6.322 + 6.323 +/** 6.324 + * Call with the command returned by android_app_read_cmd() to do the 6.325 + * initial pre-processing of the given command. You can perform your own 6.326 + * actions for the command after calling this function. 6.327 + */ 6.328 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); 6.329 + 6.330 +/** 6.331 + * Call with the command returned by android_app_read_cmd() to do the 6.332 + * final post-processing of the given command. You must have done your own 6.333 + * actions for the command before calling this function. 6.334 + */ 6.335 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); 6.336 + 6.337 +/** 6.338 + * Dummy function you can call to ensure glue code isn't stripped. 6.339 + */ 6.340 +void app_dummy(); 6.341 + 6.342 +/** 6.343 + * This is the function that application code must implement, representing 6.344 + * the main entry to the app. 6.345 + */ 6.346 +extern void android_main(struct android_app* app); 6.347 + 6.348 +#ifdef __cplusplus 6.349 +} 6.350 +#endif 6.351 + 6.352 +#endif /* _ANDROID_NATIVE_APP_GLUE_H */
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/src/app.c Thu Apr 23 20:54:02 2015 +0300 7.3 @@ -0,0 +1,80 @@ 7.4 +#include <stdio.h> 7.5 +#include <sys/time.h> 7.6 +#include <GLES/gl.h> 7.7 +#include "app.h" 7.8 + 7.9 +static unsigned int get_msec(void); 7.10 + 7.11 +int app_init(void) 7.12 +{ 7.13 + printf("app_init called\n"); 7.14 + 7.15 + return 0; 7.16 +} 7.17 + 7.18 +void app_cleanup(void) 7.19 +{ 7.20 + printf("app_cleanup called\n"); 7.21 +} 7.22 + 7.23 +static float vert_col[] = { 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1 }; 7.24 +static float vert_pos[] = { 0.0, 0.6, 0.0, -0.6, -0.4, 0.0, 0.6, -0.4, 0.0 }; 7.25 + 7.26 +void app_display(void) 7.27 +{ 7.28 + unsigned int msec = get_msec(); 7.29 + 7.30 + glClearColor(0.1, 0.1, 0.1, 1); 7.31 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 7.32 + 7.33 + glMatrixMode(GL_MODELVIEW); 7.34 + glLoadIdentity(); 7.35 + glRotatef(msec / 10.0, 0, 0, 1); 7.36 + 7.37 + glEnableClientState(GL_VERTEX_ARRAY); 7.38 + glEnableClientState(GL_COLOR_ARRAY); 7.39 + glVertexPointer(3, GL_FLOAT, 0, vert_pos); 7.40 + glColorPointer(4, GL_FLOAT, 0, vert_col); 7.41 + 7.42 + glDrawArrays(GL_TRIANGLES, 0, 3); 7.43 + 7.44 + glDisableClientState(GL_VERTEX_ARRAY); 7.45 + glDisableClientState(GL_COLOR_ARRAY); 7.46 + 7.47 + eglSwapBuffers(dpy, surf); 7.48 +} 7.49 + 7.50 +void app_resize(int x, int y) 7.51 +{ 7.52 + printf("app_resize: %dx%d\n", x, y); 7.53 + glViewport(0, 0, x, y); 7.54 + 7.55 + float aspect = (float)x / (float)y; 7.56 + glMatrixMode(GL_PROJECTION); 7.57 + glLoadIdentity(); 7.58 + glScalef(1, aspect, 1); 7.59 +} 7.60 + 7.61 +void app_touch(int id, int press, int x, int y) 7.62 +{ 7.63 + printf("app_touch: %s, id: %d, pos: %d %d\n", press ? "press" : "release", id, x, y); 7.64 +} 7.65 + 7.66 +void app_drag(int id, int x, int y) 7.67 +{ 7.68 + printf("app_drag id: %d, pos: %d %d\n", id, x, y); 7.69 +} 7.70 + 7.71 +static unsigned int get_msec(void) 7.72 +{ 7.73 + static struct timeval tv0; 7.74 + struct timeval tv; 7.75 + 7.76 + gettimeofday(&tv, 0); 7.77 + 7.78 + if(tv0.tv_sec == 0 && tv0.tv_usec == 0) { 7.79 + tv0 = tv; 7.80 + return 0; 7.81 + } 7.82 + return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000; 7.83 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/src/app.h Thu Apr 23 20:54:02 2015 +0300 8.3 @@ -0,0 +1,23 @@ 8.4 +#ifndef APP_H_ 8.5 +#define APP_H_ 8.6 + 8.7 +#include <EGL/egl.h> 8.8 + 8.9 +#ifndef APP_NAME 8.10 +#define APP_NAME "gles_test" 8.11 +#endif 8.12 + 8.13 +EGLDisplay dpy; 8.14 +EGLSurface surf; 8.15 +EGLContext ctx; 8.16 + 8.17 +int app_init(void); 8.18 +void app_cleanup(void); 8.19 + 8.20 +void app_display(void); 8.21 +void app_resize(int x, int y); 8.22 + 8.23 +void app_touch(int id, int press, int x, int y); 8.24 +void app_drag(int id, int x, int y); 8.25 + 8.26 +#endif /* APP_H_ */
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 9.2 +++ b/src/logger.c Thu Apr 23 20:54:02 2015 +0300 9.3 @@ -0,0 +1,61 @@ 9.4 +#include <stdio.h> 9.5 +#include <assert.h> 9.6 +#include <unistd.h> 9.7 +#include <pthread.h> 9.8 +#include <android/log.h> 9.9 +#include "logger.h" 9.10 +#include "app.h" 9.11 + 9.12 +static void *thread_func(void *arg); 9.13 + 9.14 +static int pfd[2]; 9.15 +static pthread_t thr; 9.16 +static int initialized; 9.17 + 9.18 +int start_logger(void) 9.19 +{ 9.20 + if(initialized) { 9.21 + return 1; 9.22 + } 9.23 + 9.24 + /* set stdout to line-buffered, and stderr to unbuffered */ 9.25 + setvbuf(stdout, 0, _IOLBF, 0); 9.26 + setvbuf(stderr, 0, _IONBF, 0); 9.27 + 9.28 + if(pipe(pfd) == -1) { 9.29 + perror("failed to create logging pipe"); 9.30 + return -1; 9.31 + } 9.32 + assert(pfd[0] > 2 && pfd[1] > 2); 9.33 + 9.34 + /* redirect stdout & stderr to the write-end of the pipe */ 9.35 + dup2(pfd[1], 1); 9.36 + dup2(pfd[1], 2); 9.37 + 9.38 + /* start the logging thread */ 9.39 + if(pthread_create(&thr, 0, thread_func, 0) == -1) { 9.40 + perror("failed to spawn logging thread"); 9.41 + return -1; 9.42 + } 9.43 + pthread_detach(thr); 9.44 + return 0; 9.45 +} 9.46 + 9.47 +static void *thread_func(void *arg) 9.48 +{ 9.49 + ssize_t rdsz; 9.50 + char buf[257]; 9.51 + 9.52 + __android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger starting up..."); 9.53 + 9.54 + while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) { 9.55 + if(buf[rdsz - 1] == '\n') { 9.56 + --rdsz; 9.57 + } 9.58 + buf[rdsz] = 0; 9.59 + __android_log_write(ANDROID_LOG_DEBUG, APP_NAME, buf); 9.60 + } 9.61 + 9.62 + __android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger shutting down..."); 9.63 + return 0; 9.64 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 10.2 +++ b/src/logger.h Thu Apr 23 20:54:02 2015 +0300 10.3 @@ -0,0 +1,6 @@ 10.4 +#ifndef LOGGER_H_ 10.5 +#define LOGGER_H_ 10.6 + 10.7 +int start_logger(void); 10.8 + 10.9 +#endif /* LOGGER_H_ */
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 11.2 +++ b/src/main.c Thu Apr 23 20:54:02 2015 +0300 11.3 @@ -0,0 +1,240 @@ 11.4 +#include <stdio.h> 11.5 +#include <stdlib.h> 11.6 +#include <string.h> 11.7 +#include <GLES/gl.h> 11.8 +#include <GLES/glext.h> 11.9 +#include <EGL/egl.h> 11.10 +#include <android_native_app_glue.h> 11.11 +#include "app.h" 11.12 +#include "logger.h" 11.13 + 11.14 +static void handle_command(struct android_app *app, int32_t cmd); 11.15 +static int handle_input(struct android_app *app, AInputEvent *ev); 11.16 +static int handle_touch_input(struct android_app *app, AInputEvent *ev); 11.17 +static int init_gl(void); 11.18 +static void destroy_gl(void); 11.19 + 11.20 +static struct android_app *app; 11.21 +static int win_width, win_height; 11.22 + 11.23 +void android_main(struct android_app *app_ptr) 11.24 +{ 11.25 + app_dummy(); 11.26 + app = app_ptr; 11.27 + 11.28 + app->onAppCmd = handle_command; 11.29 + app->onInputEvent = handle_input; 11.30 + 11.31 + start_logger(); 11.32 + 11.33 + for(;;) { 11.34 + int num_events; 11.35 + struct android_poll_source *pollsrc; 11.36 + 11.37 + while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) { 11.38 + if(pollsrc) { 11.39 + pollsrc->process(app, pollsrc); 11.40 + } 11.41 + } 11.42 + 11.43 + if(app->destroyRequested) { 11.44 + return; 11.45 + } 11.46 + 11.47 + app_display(); 11.48 + } 11.49 +} 11.50 + 11.51 +static void handle_command(struct android_app *app, int32_t cmd) 11.52 +{ 11.53 + switch(cmd) { 11.54 + case APP_CMD_SAVE_STATE: 11.55 + /* save the application state to be reloaded on restart if needed */ 11.56 + break; 11.57 + 11.58 + case APP_CMD_INIT_WINDOW: 11.59 + if(init_gl() == -1) { 11.60 + exit(1); 11.61 + } 11.62 + /* initialize the application */ 11.63 + if(app_init() == -1) { 11.64 + exit(1); /* initialization failed, quit */ 11.65 + } 11.66 + break; 11.67 + 11.68 + case APP_CMD_TERM_WINDOW: 11.69 + /* cleanup */ 11.70 + app_cleanup(); 11.71 + destroy_gl(); 11.72 + break; 11.73 + 11.74 + case APP_CMD_GAINED_FOCUS: 11.75 + /* app focused */ 11.76 + break; 11.77 + 11.78 + case APP_CMD_LOST_FOCUS: 11.79 + /* app lost focus */ 11.80 + break; 11.81 + 11.82 + case APP_CMD_WINDOW_RESIZED: 11.83 + case APP_CMD_CONFIG_CHANGED: 11.84 + { 11.85 + int nx = ANativeWindow_getWidth(app->window); 11.86 + int ny = ANativeWindow_getHeight(app->window); 11.87 + if(nx != win_width || ny != win_height) { 11.88 + app_resize(nx, ny); 11.89 + win_width = nx; 11.90 + win_height = ny; 11.91 + } 11.92 + } 11.93 + break; 11.94 + 11.95 + default: 11.96 + break; 11.97 + } 11.98 +} 11.99 + 11.100 +static int handle_input(struct android_app *app, AInputEvent *ev) 11.101 +{ 11.102 + int evtype = AInputEvent_getType(ev); 11.103 + 11.104 + switch(evtype) { 11.105 + case AINPUT_EVENT_TYPE_MOTION: 11.106 + return handle_touch_input(app, ev); 11.107 + 11.108 + default: 11.109 + break; 11.110 + } 11.111 + return 0; 11.112 +} 11.113 + 11.114 +#define MAX_TOUCH_IDS 32 11.115 + 11.116 +static int handle_touch_input(struct android_app *app, AInputEvent *ev) 11.117 +{ 11.118 + int x, y, idx, touch_id; 11.119 + unsigned int action; 11.120 + static int prev_pos[MAX_TOUCH_IDS][2]; 11.121 + 11.122 + action = AMotionEvent_getAction(ev); 11.123 + 11.124 + idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> 11.125 + AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; 11.126 + touch_id = AMotionEvent_getPointerId(ev, idx); 11.127 + 11.128 + x = AMotionEvent_getX(ev, idx); 11.129 + y = AMotionEvent_getY(ev, idx); 11.130 + 11.131 + switch(action & AMOTION_EVENT_ACTION_MASK) { 11.132 + case AMOTION_EVENT_ACTION_DOWN: 11.133 + case AMOTION_EVENT_ACTION_POINTER_DOWN: 11.134 + app_touch(touch_id, 1, x, y); 11.135 + if(touch_id < MAX_TOUCH_IDS) { 11.136 + prev_pos[touch_id][0] = x; 11.137 + prev_pos[touch_id][1] = y; 11.138 + } 11.139 + break; 11.140 + 11.141 + case AMOTION_EVENT_ACTION_UP: 11.142 + case AMOTION_EVENT_ACTION_POINTER_UP: 11.143 + app_touch(touch_id, 0, x, y); 11.144 + if(touch_id < MAX_TOUCH_IDS) { 11.145 + prev_pos[touch_id][0] = x; 11.146 + prev_pos[touch_id][1] = y; 11.147 + } 11.148 + break; 11.149 + 11.150 + case AMOTION_EVENT_ACTION_MOVE: 11.151 + { 11.152 + int i, pcount = AMotionEvent_getPointerCount(ev); 11.153 + for(i=0; i<pcount; i++) { 11.154 + int id = AMotionEvent_getPointerId(ev, i); 11.155 + if(id < MAX_TOUCH_IDS && x != prev_pos[id][0] && y != prev_pos[id][1]) { 11.156 + app_drag(id, x, y); 11.157 + prev_pos[id][0] = x; 11.158 + prev_pos[id][1] = y; 11.159 + } 11.160 + } 11.161 + } 11.162 + break; 11.163 + 11.164 + default: 11.165 + break; 11.166 + } 11.167 + 11.168 + return 1; 11.169 +} 11.170 + 11.171 + 11.172 +static int init_gl(void) 11.173 +{ 11.174 + static const int eglattr[] = { 11.175 + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, 11.176 + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, 11.177 + EGL_RED_SIZE, 5, 11.178 + EGL_GREEN_SIZE, 5, 11.179 + EGL_BLUE_SIZE, 5, 11.180 + EGL_DEPTH_SIZE, 16, 11.181 + EGL_NONE 11.182 + }; 11.183 + static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE }; 11.184 + 11.185 + EGLConfig eglcfg; 11.186 + int count, vis; 11.187 + 11.188 + dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY); 11.189 + if(!dpy || !eglInitialize(dpy, 0, 0)) { 11.190 + fprintf(stderr, "failed to initialize EGL\n"); 11.191 + destroy_gl(); 11.192 + return -1; 11.193 + } 11.194 + 11.195 + if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) { 11.196 + fprintf(stderr, "no matching EGL config found\n"); 11.197 + destroy_gl(); 11.198 + return -1; 11.199 + } 11.200 + 11.201 + /* configure the native window visual according to the chosen EGL config */ 11.202 + eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis); 11.203 + ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis); 11.204 + 11.205 + if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) { 11.206 + fprintf(stderr, "failed to create window\n"); 11.207 + destroy_gl(); 11.208 + return -1; 11.209 + } 11.210 + 11.211 + if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) { 11.212 + fprintf(stderr, "failed to create OpenGL ES context\n"); 11.213 + destroy_gl(); 11.214 + return -1; 11.215 + } 11.216 + eglMakeCurrent(dpy, surf, surf, ctx); 11.217 + 11.218 + eglQuerySurface(dpy, surf, EGL_WIDTH, &win_width); 11.219 + eglQuerySurface(dpy, surf, EGL_HEIGHT, &win_height); 11.220 + app_resize(win_width, win_height); 11.221 + 11.222 + return 0; 11.223 +} 11.224 + 11.225 +static void destroy_gl(void) 11.226 +{ 11.227 + if(!dpy) return; 11.228 + 11.229 + eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 11.230 + 11.231 + if(ctx) { 11.232 + eglDestroyContext(dpy, ctx); 11.233 + ctx = 0; 11.234 + } 11.235 + if(surf) { 11.236 + eglDestroySurface(dpy, surf); 11.237 + surf = 0; 11.238 + } 11.239 + 11.240 + eglTerminate(dpy); 11.241 + dpy = 0; 11.242 +} 11.243 +