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 +}