istereo2
diff src/android/android_native_app_glue.c @ 23:7d795dade0bc
first pass at android port... compiles!
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 03 Oct 2015 06:10:30 +0300 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/android/android_native_app_glue.c Sat Oct 03 06:10:30 2015 +0300 1.3 @@ -0,0 +1,440 @@ 1.4 +/* 1.5 + * Copyright (C) 2010 The Android Open Source Project 1.6 + * 1.7 + * Licensed under the Apache License, Version 2.0 (the "License"); 1.8 + * you may not use this file except in compliance with the License. 1.9 + * You may obtain a copy of the License at 1.10 + * 1.11 + * http://www.apache.org/licenses/LICENSE-2.0 1.12 + * 1.13 + * Unless required by applicable law or agreed to in writing, software 1.14 + * distributed under the License is distributed on an "AS IS" BASIS, 1.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.16 + * See the License for the specific language governing permissions and 1.17 + * limitations under the License. 1.18 + * 1.19 + */ 1.20 + 1.21 +#include <jni.h> 1.22 + 1.23 +#include <errno.h> 1.24 +#include <string.h> 1.25 +#include <unistd.h> 1.26 +#include <sys/resource.h> 1.27 + 1.28 +#include "android_native_app_glue.h" 1.29 +#include <android/log.h> 1.30 + 1.31 +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) 1.32 +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) 1.33 + 1.34 +/* For debug builds, always enable the debug traces in this library */ 1.35 +#ifndef NDEBUG 1.36 +# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) 1.37 +#else 1.38 +# define LOGV(...) ((void)0) 1.39 +#endif 1.40 + 1.41 +static void free_saved_state(struct android_app* android_app) { 1.42 + pthread_mutex_lock(&android_app->mutex); 1.43 + if (android_app->savedState != NULL) { 1.44 + free(android_app->savedState); 1.45 + android_app->savedState = NULL; 1.46 + android_app->savedStateSize = 0; 1.47 + } 1.48 + pthread_mutex_unlock(&android_app->mutex); 1.49 +} 1.50 + 1.51 +int8_t android_app_read_cmd(struct android_app* android_app) { 1.52 + int8_t cmd; 1.53 + if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { 1.54 + switch (cmd) { 1.55 + case APP_CMD_SAVE_STATE: 1.56 + free_saved_state(android_app); 1.57 + break; 1.58 + } 1.59 + return cmd; 1.60 + } else { 1.61 + LOGE("No data on command pipe!"); 1.62 + } 1.63 + return -1; 1.64 +} 1.65 + 1.66 +static void print_cur_config(struct android_app* android_app) { 1.67 + char lang[2], country[2]; 1.68 + AConfiguration_getLanguage(android_app->config, lang); 1.69 + AConfiguration_getCountry(android_app->config, country); 1.70 + 1.71 + LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " 1.72 + "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " 1.73 + "modetype=%d modenight=%d", 1.74 + AConfiguration_getMcc(android_app->config), 1.75 + AConfiguration_getMnc(android_app->config), 1.76 + lang[0], lang[1], country[0], country[1], 1.77 + AConfiguration_getOrientation(android_app->config), 1.78 + AConfiguration_getTouchscreen(android_app->config), 1.79 + AConfiguration_getDensity(android_app->config), 1.80 + AConfiguration_getKeyboard(android_app->config), 1.81 + AConfiguration_getNavigation(android_app->config), 1.82 + AConfiguration_getKeysHidden(android_app->config), 1.83 + AConfiguration_getNavHidden(android_app->config), 1.84 + AConfiguration_getSdkVersion(android_app->config), 1.85 + AConfiguration_getScreenSize(android_app->config), 1.86 + AConfiguration_getScreenLong(android_app->config), 1.87 + AConfiguration_getUiModeType(android_app->config), 1.88 + AConfiguration_getUiModeNight(android_app->config)); 1.89 +} 1.90 + 1.91 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { 1.92 + switch (cmd) { 1.93 + case APP_CMD_INPUT_CHANGED: 1.94 + LOGV("APP_CMD_INPUT_CHANGED\n"); 1.95 + pthread_mutex_lock(&android_app->mutex); 1.96 + if (android_app->inputQueue != NULL) { 1.97 + AInputQueue_detachLooper(android_app->inputQueue); 1.98 + } 1.99 + android_app->inputQueue = android_app->pendingInputQueue; 1.100 + if (android_app->inputQueue != NULL) { 1.101 + LOGV("Attaching input queue to looper"); 1.102 + AInputQueue_attachLooper(android_app->inputQueue, 1.103 + android_app->looper, LOOPER_ID_INPUT, NULL, 1.104 + &android_app->inputPollSource); 1.105 + } 1.106 + pthread_cond_broadcast(&android_app->cond); 1.107 + pthread_mutex_unlock(&android_app->mutex); 1.108 + break; 1.109 + 1.110 + case APP_CMD_INIT_WINDOW: 1.111 + LOGV("APP_CMD_INIT_WINDOW\n"); 1.112 + pthread_mutex_lock(&android_app->mutex); 1.113 + android_app->window = android_app->pendingWindow; 1.114 + pthread_cond_broadcast(&android_app->cond); 1.115 + pthread_mutex_unlock(&android_app->mutex); 1.116 + break; 1.117 + 1.118 + case APP_CMD_TERM_WINDOW: 1.119 + LOGV("APP_CMD_TERM_WINDOW\n"); 1.120 + pthread_cond_broadcast(&android_app->cond); 1.121 + break; 1.122 + 1.123 + case APP_CMD_RESUME: 1.124 + case APP_CMD_START: 1.125 + case APP_CMD_PAUSE: 1.126 + case APP_CMD_STOP: 1.127 + LOGV("activityState=%d\n", cmd); 1.128 + pthread_mutex_lock(&android_app->mutex); 1.129 + android_app->activityState = cmd; 1.130 + pthread_cond_broadcast(&android_app->cond); 1.131 + pthread_mutex_unlock(&android_app->mutex); 1.132 + break; 1.133 + 1.134 + case APP_CMD_CONFIG_CHANGED: 1.135 + LOGV("APP_CMD_CONFIG_CHANGED\n"); 1.136 + AConfiguration_fromAssetManager(android_app->config, 1.137 + android_app->activity->assetManager); 1.138 + print_cur_config(android_app); 1.139 + break; 1.140 + 1.141 + case APP_CMD_DESTROY: 1.142 + LOGV("APP_CMD_DESTROY\n"); 1.143 + android_app->destroyRequested = 1; 1.144 + break; 1.145 + } 1.146 +} 1.147 + 1.148 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { 1.149 + switch (cmd) { 1.150 + case APP_CMD_TERM_WINDOW: 1.151 + LOGV("APP_CMD_TERM_WINDOW\n"); 1.152 + pthread_mutex_lock(&android_app->mutex); 1.153 + android_app->window = NULL; 1.154 + pthread_cond_broadcast(&android_app->cond); 1.155 + pthread_mutex_unlock(&android_app->mutex); 1.156 + break; 1.157 + 1.158 + case APP_CMD_SAVE_STATE: 1.159 + LOGV("APP_CMD_SAVE_STATE\n"); 1.160 + pthread_mutex_lock(&android_app->mutex); 1.161 + android_app->stateSaved = 1; 1.162 + pthread_cond_broadcast(&android_app->cond); 1.163 + pthread_mutex_unlock(&android_app->mutex); 1.164 + break; 1.165 + 1.166 + case APP_CMD_RESUME: 1.167 + free_saved_state(android_app); 1.168 + break; 1.169 + } 1.170 +} 1.171 + 1.172 +void app_dummy() { 1.173 + 1.174 +} 1.175 + 1.176 +static void android_app_destroy(struct android_app* android_app) { 1.177 + LOGV("android_app_destroy!"); 1.178 + free_saved_state(android_app); 1.179 + pthread_mutex_lock(&android_app->mutex); 1.180 + if (android_app->inputQueue != NULL) { 1.181 + AInputQueue_detachLooper(android_app->inputQueue); 1.182 + } 1.183 + AConfiguration_delete(android_app->config); 1.184 + android_app->destroyed = 1; 1.185 + pthread_cond_broadcast(&android_app->cond); 1.186 + pthread_mutex_unlock(&android_app->mutex); 1.187 + // Can't touch android_app object after this. 1.188 +} 1.189 + 1.190 +static void process_input(struct android_app* app, struct android_poll_source* source) { 1.191 + AInputEvent* event = NULL; 1.192 + while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { 1.193 + LOGV("New input event: type=%d\n", AInputEvent_getType(event)); 1.194 + if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { 1.195 + continue; 1.196 + } 1.197 + int32_t handled = 0; 1.198 + if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); 1.199 + AInputQueue_finishEvent(app->inputQueue, event, handled); 1.200 + } 1.201 +} 1.202 + 1.203 +static void process_cmd(struct android_app* app, struct android_poll_source* source) { 1.204 + int8_t cmd = android_app_read_cmd(app); 1.205 + android_app_pre_exec_cmd(app, cmd); 1.206 + if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); 1.207 + android_app_post_exec_cmd(app, cmd); 1.208 +} 1.209 + 1.210 +static void* android_app_entry(void* param) { 1.211 + struct android_app* android_app = (struct android_app*)param; 1.212 + 1.213 + android_app->config = AConfiguration_new(); 1.214 + AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); 1.215 + 1.216 + print_cur_config(android_app); 1.217 + 1.218 + android_app->cmdPollSource.id = LOOPER_ID_MAIN; 1.219 + android_app->cmdPollSource.app = android_app; 1.220 + android_app->cmdPollSource.process = process_cmd; 1.221 + android_app->inputPollSource.id = LOOPER_ID_INPUT; 1.222 + android_app->inputPollSource.app = android_app; 1.223 + android_app->inputPollSource.process = process_input; 1.224 + 1.225 + ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); 1.226 + ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, 1.227 + &android_app->cmdPollSource); 1.228 + android_app->looper = looper; 1.229 + 1.230 + pthread_mutex_lock(&android_app->mutex); 1.231 + android_app->running = 1; 1.232 + pthread_cond_broadcast(&android_app->cond); 1.233 + pthread_mutex_unlock(&android_app->mutex); 1.234 + 1.235 + android_main(android_app); 1.236 + 1.237 + android_app_destroy(android_app); 1.238 + return NULL; 1.239 +} 1.240 + 1.241 +// -------------------------------------------------------------------- 1.242 +// Native activity interaction (called from main thread) 1.243 +// -------------------------------------------------------------------- 1.244 + 1.245 +static struct android_app* android_app_create(ANativeActivity* activity, 1.246 + void* savedState, size_t savedStateSize) { 1.247 + struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); 1.248 + memset(android_app, 0, sizeof(struct android_app)); 1.249 + android_app->activity = activity; 1.250 + 1.251 + pthread_mutex_init(&android_app->mutex, NULL); 1.252 + pthread_cond_init(&android_app->cond, NULL); 1.253 + 1.254 + if (savedState != NULL) { 1.255 + android_app->savedState = malloc(savedStateSize); 1.256 + android_app->savedStateSize = savedStateSize; 1.257 + memcpy(android_app->savedState, savedState, savedStateSize); 1.258 + } 1.259 + 1.260 + int msgpipe[2]; 1.261 + if (pipe(msgpipe)) { 1.262 + LOGE("could not create pipe: %s", strerror(errno)); 1.263 + return NULL; 1.264 + } 1.265 + android_app->msgread = msgpipe[0]; 1.266 + android_app->msgwrite = msgpipe[1]; 1.267 + 1.268 + pthread_attr_t attr; 1.269 + pthread_attr_init(&attr); 1.270 + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 1.271 + pthread_create(&android_app->thread, &attr, android_app_entry, android_app); 1.272 + 1.273 + // Wait for thread to start. 1.274 + pthread_mutex_lock(&android_app->mutex); 1.275 + while (!android_app->running) { 1.276 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.277 + } 1.278 + pthread_mutex_unlock(&android_app->mutex); 1.279 + 1.280 + return android_app; 1.281 +} 1.282 + 1.283 +static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { 1.284 + if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { 1.285 + LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); 1.286 + } 1.287 +} 1.288 + 1.289 +static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { 1.290 + pthread_mutex_lock(&android_app->mutex); 1.291 + android_app->pendingInputQueue = inputQueue; 1.292 + android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); 1.293 + while (android_app->inputQueue != android_app->pendingInputQueue) { 1.294 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.295 + } 1.296 + pthread_mutex_unlock(&android_app->mutex); 1.297 +} 1.298 + 1.299 +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { 1.300 + pthread_mutex_lock(&android_app->mutex); 1.301 + if (android_app->pendingWindow != NULL) { 1.302 + android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); 1.303 + } 1.304 + android_app->pendingWindow = window; 1.305 + if (window != NULL) { 1.306 + android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); 1.307 + } 1.308 + while (android_app->window != android_app->pendingWindow) { 1.309 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.310 + } 1.311 + pthread_mutex_unlock(&android_app->mutex); 1.312 +} 1.313 + 1.314 +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { 1.315 + pthread_mutex_lock(&android_app->mutex); 1.316 + android_app_write_cmd(android_app, cmd); 1.317 + while (android_app->activityState != cmd) { 1.318 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.319 + } 1.320 + pthread_mutex_unlock(&android_app->mutex); 1.321 +} 1.322 + 1.323 +static void android_app_free(struct android_app* android_app) { 1.324 + pthread_mutex_lock(&android_app->mutex); 1.325 + android_app_write_cmd(android_app, APP_CMD_DESTROY); 1.326 + while (!android_app->destroyed) { 1.327 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.328 + } 1.329 + pthread_mutex_unlock(&android_app->mutex); 1.330 + 1.331 + close(android_app->msgread); 1.332 + close(android_app->msgwrite); 1.333 + pthread_cond_destroy(&android_app->cond); 1.334 + pthread_mutex_destroy(&android_app->mutex); 1.335 + free(android_app); 1.336 +} 1.337 + 1.338 +static void onDestroy(ANativeActivity* activity) { 1.339 + LOGV("Destroy: %p\n", activity); 1.340 + android_app_free((struct android_app*)activity->instance); 1.341 +} 1.342 + 1.343 +static void onStart(ANativeActivity* activity) { 1.344 + LOGV("Start: %p\n", activity); 1.345 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); 1.346 +} 1.347 + 1.348 +static void onResume(ANativeActivity* activity) { 1.349 + LOGV("Resume: %p\n", activity); 1.350 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); 1.351 +} 1.352 + 1.353 +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { 1.354 + struct android_app* android_app = (struct android_app*)activity->instance; 1.355 + void* savedState = NULL; 1.356 + 1.357 + LOGV("SaveInstanceState: %p\n", activity); 1.358 + pthread_mutex_lock(&android_app->mutex); 1.359 + android_app->stateSaved = 0; 1.360 + android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); 1.361 + while (!android_app->stateSaved) { 1.362 + pthread_cond_wait(&android_app->cond, &android_app->mutex); 1.363 + } 1.364 + 1.365 + if (android_app->savedState != NULL) { 1.366 + savedState = android_app->savedState; 1.367 + *outLen = android_app->savedStateSize; 1.368 + android_app->savedState = NULL; 1.369 + android_app->savedStateSize = 0; 1.370 + } 1.371 + 1.372 + pthread_mutex_unlock(&android_app->mutex); 1.373 + 1.374 + return savedState; 1.375 +} 1.376 + 1.377 +static void onPause(ANativeActivity* activity) { 1.378 + LOGV("Pause: %p\n", activity); 1.379 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); 1.380 +} 1.381 + 1.382 +static void onStop(ANativeActivity* activity) { 1.383 + LOGV("Stop: %p\n", activity); 1.384 + android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); 1.385 +} 1.386 + 1.387 +static void onConfigurationChanged(ANativeActivity* activity) { 1.388 + struct android_app* android_app = (struct android_app*)activity->instance; 1.389 + LOGV("ConfigurationChanged: %p\n", activity); 1.390 + android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); 1.391 +} 1.392 + 1.393 +static void onLowMemory(ANativeActivity* activity) { 1.394 + struct android_app* android_app = (struct android_app*)activity->instance; 1.395 + LOGV("LowMemory: %p\n", activity); 1.396 + android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); 1.397 +} 1.398 + 1.399 +static void onWindowFocusChanged(ANativeActivity* activity, int focused) { 1.400 + LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); 1.401 + android_app_write_cmd((struct android_app*)activity->instance, 1.402 + focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); 1.403 +} 1.404 + 1.405 +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { 1.406 + LOGV("NativeWindowCreated: %p -- %p\n", activity, window); 1.407 + android_app_set_window((struct android_app*)activity->instance, window); 1.408 +} 1.409 + 1.410 +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { 1.411 + LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); 1.412 + android_app_set_window((struct android_app*)activity->instance, NULL); 1.413 +} 1.414 + 1.415 +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { 1.416 + LOGV("InputQueueCreated: %p -- %p\n", activity, queue); 1.417 + android_app_set_input((struct android_app*)activity->instance, queue); 1.418 +} 1.419 + 1.420 +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { 1.421 + LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); 1.422 + android_app_set_input((struct android_app*)activity->instance, NULL); 1.423 +} 1.424 + 1.425 +void ANativeActivity_onCreate(ANativeActivity* activity, 1.426 + void* savedState, size_t savedStateSize) { 1.427 + LOGV("Creating: %p\n", activity); 1.428 + activity->callbacks->onDestroy = onDestroy; 1.429 + activity->callbacks->onStart = onStart; 1.430 + activity->callbacks->onResume = onResume; 1.431 + activity->callbacks->onSaveInstanceState = onSaveInstanceState; 1.432 + activity->callbacks->onPause = onPause; 1.433 + activity->callbacks->onStop = onStop; 1.434 + activity->callbacks->onConfigurationChanged = onConfigurationChanged; 1.435 + activity->callbacks->onLowMemory = onLowMemory; 1.436 + activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; 1.437 + activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; 1.438 + activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; 1.439 + activity->callbacks->onInputQueueCreated = onInputQueueCreated; 1.440 + activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; 1.441 + 1.442 + activity->instance = android_app_create(activity, savedState, savedStateSize); 1.443 +}