istereo2

changeset 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 c6971ff4795e
children 9d53a4938ce8
files .hgignore android/Makefile android/manifest.xml.in libs/Makefile src/android/amain.c src/android/android_native_app_glue.c src/android/android_native_app_glue.h src/android/assman.c src/android/logger.c src/android/logger.h src/opengl.h
diffstat 11 files changed, 1290 insertions(+), 12 deletions(-) [+]
line diff
     1.1 --- a/.hgignore	Fri Oct 02 07:10:19 2015 +0300
     1.2 +++ b/.hgignore	Sat Oct 03 06:10:30 2015 +0300
     1.3 @@ -11,3 +11,11 @@
     1.4  ^data/
     1.5  \.DS_Store
     1.6  ^test$
     1.7 +^android/bin/
     1.8 +^android/libs/
     1.9 +^android/res/
    1.10 +^android/src/
    1.11 +^android/assets/
    1.12 +\.xml$
    1.13 +\.properties$
    1.14 +proguard-project\.txt$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/android/Makefile	Sat Oct 03 06:10:30 2015 +0300
     2.3 @@ -0,0 +1,106 @@
     2.4 +bin = stereotunnel
     2.5 +root = ..
     2.6 +src = $(wildcard $(root)/src/*.c)
     2.7 +ccsrc = $(wildcard $(root)/src/*.cc)
     2.8 +
     2.9 +include $(root)/libs/Makefile
    2.10 +
    2.11 +# --- android settings ---
    2.12 +android_platform = android-19
    2.13 +name = $(bin)
    2.14 +pkgprefix = com.mutantstargoat
    2.15 +# ------------------------
    2.16 +
    2.17 +src += $(wildcard $(root)/src/android/*.c)
    2.18 +
    2.19 +obj = $(src:.c=.o) $(ccsrc:.cc=.o)
    2.20 +lib = libs/armeabi/lib$(name).so
    2.21 +apk-release = bin/$(name).apk
    2.22 +apk-debug = bin/$(name)-debug.apk
    2.23 +
    2.24 +pkg = $(pkgprefix).$(name)
    2.25 +act = android.app.NativeActivity
    2.26 +
    2.27 +CC = arm-linux-androideabi-gcc
    2.28 +CXX = arm-linux-androideabi-g++
    2.29 +
    2.30 +android_libs = -lstdc++ -llog -landroid -lEGL -lGLESv2
    2.31 +
    2.32 +defs += -DANDROID -DAPP_NAME=\"$(name)\" -DNO_FREETYPE -DHAVE_OPENGL_H
    2.33 +CXXFLAGS = -Wall -g $(defs) -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 \
    2.34 +		 $(android_inc) -I$(root)/src -I$(root)/src/android $(incdir)
    2.35 +CFLAGS = -std=c99 $(CXXFLAGS)
    2.36 +LDFLAGS = -Wl,--fix-cortex-a8 -Wl,-z,defs $(android_libs) $(libpaths) -lm
    2.37 +
    2.38 +.PHONY: debug
    2.39 +debug: $(apk-debug)
    2.40 +
    2.41 +.PHONY: release
    2.42 +release: $(apk-release)
    2.43 +
    2.44 +$(apk-debug): $(lib) $(jsrc) AndroidManifest.xml assets/data assets/sdr
    2.45 +	ant debug
    2.46 +
    2.47 +$(apk-release): $(lib) $(jsrc) AndroidManifest.xml assets/data assets/sdr
    2.48 +	ant release
    2.49 +
    2.50 +assets/data:
    2.51 +	mkdir -p assets
    2.52 +	cd assets && rm -f data && ln -s ../../data .
    2.53 +
    2.54 +assets/sdr:
    2.55 +	mkdir -p assets
    2.56 +	cd assets && rm -f sdr && ln -s ../../sdr .
    2.57 +
    2.58 +.PHONY: lib
    2.59 +lib: $(lib)
    2.60 +
    2.61 +$(lib): $(obj)
    2.62 +	@mkdir -p libs/armeabi
    2.63 +	$(CXX) -o $@ -shared $(obj) $(LDFLAGS)
    2.64 +
    2.65 +ant_files = *.xml *.properties proguard-project.txt
    2.66 +ant_dirs = bin libs res obj src gen
    2.67 +
    2.68 +.PHONY: clean
    2.69 +clean:
    2.70 +	rm -f $(obj) $(lib) $(apk-release) $(apk-debug) $(ant_files)
    2.71 +	rm -rf $(ant_dirs)
    2.72 +	rm -f assets/data assets/sdr
    2.73 +	[ -d assets ] && rmdir assets || true
    2.74 +
    2.75 +.PHONY: install
    2.76 +install: install-debug
    2.77 +
    2.78 +.PHONY: install-debug
    2.79 +install-debug:
    2.80 +	adb install -r $(apk-debug)
    2.81 +
    2.82 +.PHONY: install-release
    2.83 +install-release:
    2.84 +	adb install -r $(apk-release)
    2.85 +
    2.86 +.PHONY: uninstall
    2.87 +uninstall:
    2.88 +	adb uninstall $(pkg)
    2.89 +
    2.90 +.PHONY: run
    2.91 +run:
    2.92 +	adb shell am start -n $(pkg)/$(act)
    2.93 +
    2.94 +.PHONY: stop
    2.95 +stop:
    2.96 +	adb shell am force-stop $(pkg)
    2.97 +
    2.98 +AndroidManifest.xml: manifest.xml.in
    2.99 +	android create project -p . -t $(android_platform) -k $(pkg) -a NativeActivity -n $(name)
   2.100 +	cat manifest.xml.in | sed 's/$$APPNAME/$(name)/g' | sed 's/$$APPTITLE/$(title)/g' >$@
   2.101 +#	cd src && rm -f *.java && ln -s ../../src/android/*.java .
   2.102 +
   2.103 +.PHONY: update-project
   2.104 +update-project: build.xml
   2.105 +	android update project -p . -t $(android_platform)
   2.106 +
   2.107 +.PHONY: logcat
   2.108 +logcat:
   2.109 +	adb logcat $(name):V AndroidRuntime:V DEBUG:V '*:S'
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/android/manifest.xml.in	Sat Oct 03 06:10:30 2015 +0300
     3.3 @@ -0,0 +1,25 @@
     3.4 +<?xml version="1.0" encoding="utf-8"?>
     3.5 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3.6 +	package="com.mutantstargoat.$APPNAME"
     3.7 +	android:versionCode="1"
     3.8 +	android:versionName="1.0">
     3.9 +
    3.10 +	<uses-sdk android:minSdkVersion="9"/>
    3.11 +
    3.12 +	<application android:label="$APPNAME"
    3.13 +			android:hasCode="false"
    3.14 +			android:debuggable="true">
    3.15 +			<!-- android:icon="@drawable/ic_launcher" -->
    3.16 +
    3.17 +		<activity android:name="android.app.NativeActivity"
    3.18 +			android:label="$APPTITLE">
    3.19 +
    3.20 +			<meta-data android:name="android.app.lib_name" android:value="$APPNAME"/>
    3.21 +
    3.22 +			<intent-filter>
    3.23 +				<action android:name="android.intent.action.MAIN" />
    3.24 +				<category android:name="android.intent.category.LAUNCHER" />
    3.25 +			</intent-filter>
    3.26 +		</activity>
    3.27 +	</application>
    3.28 +</manifest>
     4.1 --- a/libs/Makefile	Fri Oct 02 07:10:19 2015 +0300
     4.2 +++ b/libs/Makefile	Sat Oct 03 06:10:30 2015 +0300
     4.3 @@ -1,11 +1,12 @@
     4.4 -src += $(wildcard libs/zlib/*.c) \
     4.5 -	   $(wildcard libs/libpng/*.c) \
     4.6 -	   $(wildcard libs/libjpeg/*.c) \
     4.7 -	   $(wildcard libs/imago2/*.c) \
     4.8 -	   $(wildcard libs/vmath/*.c) \
     4.9 -	   $(wildcard libs/drawtext/*.c)
    4.10 +src += $(wildcard $(root)/libs/zlib/*.c) \
    4.11 +	   $(wildcard $(root)/libs/libpng/*.c) \
    4.12 +	   $(wildcard $(root)/libs/libjpeg/*.c) \
    4.13 +	   $(wildcard $(root)/libs/imago2/*.c) \
    4.14 +	   $(wildcard $(root)/libs/vmath/*.c) \
    4.15 +	   $(wildcard $(root)/libs/drawtext/*.c)
    4.16  
    4.17 -ccsrc += $(wildcard libs/goatkit/*.cc)
    4.18 +ccsrc += $(wildcard $(root)/libs/goatkit/*.cc)
    4.19  
    4.20 -incdir += -Ilibs -Ilibs/imago2 -Ilibs/zlib -Ilibs/libpng -Ilibs/libjpeg \
    4.21 -		  -Ilibs/vmath -Ilibs/drawtext
    4.22 +incdir += -I$(root)/libs -I$(root)/libs/imago2 -I$(root)/libs/zlib \
    4.23 +		  -I$(root)/libs/libpng -I$(root)/libs/libjpeg \
    4.24 +		  -I$(root)/libs/vmath -I$(root)/libs/drawtext
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/android/amain.c	Sat Oct 03 06:10:30 2015 +0300
     5.3 @@ -0,0 +1,275 @@
     5.4 +#include <stdio.h>
     5.5 +#include <stdlib.h>
     5.6 +#include <assert.h>
     5.7 +#include <EGL/egl.h>
     5.8 +#include <jni.h>
     5.9 +#include "android_native_app_glue.h"
    5.10 +#include <android/sensor.h>
    5.11 +#include "logger.h"
    5.12 +#include "istereo.h"
    5.13 +
    5.14 +struct android_app *app;
    5.15 +
    5.16 +static void handle_command(struct android_app *app, int32_t cmd);
    5.17 +static int handle_input(struct android_app *app, AInputEvent *ev);
    5.18 +static int handle_touch_input(struct android_app *app, AInputEvent *ev);
    5.19 +static int init_gl(void);
    5.20 +static void destroy_gl(void);
    5.21 +
    5.22 +static EGLDisplay dpy;
    5.23 +static EGLSurface surf;
    5.24 +static EGLContext ctx;
    5.25 +
    5.26 +static int redisp_pending = 1;	/* TODO stop busy-looping */
    5.27 +
    5.28 +static int width, height;
    5.29 +static int init_done;
    5.30 +
    5.31 +void android_main(struct android_app *app_ptr)
    5.32 +{
    5.33 +	app_dummy();
    5.34 +	app = app_ptr;
    5.35 +
    5.36 +	app->onAppCmd = handle_command;
    5.37 +	app->onInputEvent = handle_input;
    5.38 +
    5.39 +	start_logger();
    5.40 +
    5.41 +	for(;;) {
    5.42 +		int num_events;
    5.43 +		struct android_poll_source *pollsrc;
    5.44 +
    5.45 +		while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) {
    5.46 +			if(pollsrc) {
    5.47 +				pollsrc->process(app, pollsrc);
    5.48 +			}
    5.49 +		}
    5.50 +
    5.51 +		if(app->destroyRequested) {
    5.52 +			return;
    5.53 +		}
    5.54 +
    5.55 +		if(init_done && redisp_pending) {
    5.56 +			redraw();
    5.57 +			eglSwapBuffers(dpy, surf);
    5.58 +		}
    5.59 +	}
    5.60 +}
    5.61 +
    5.62 +void set_mouse_pos(int x, int y)
    5.63 +{
    5.64 +}
    5.65 +
    5.66 +void set_mouse_cursor(int enable)
    5.67 +{
    5.68 +}
    5.69 +
    5.70 +/* TODO */
    5.71 +void ad_banner_show(void)
    5.72 +{
    5.73 +}
    5.74 +
    5.75 +void ad_banner_hide(void)
    5.76 +{
    5.77 +}
    5.78 +
    5.79 +static void handle_command(struct android_app *app, int32_t cmd)
    5.80 +{
    5.81 +	switch(cmd) {
    5.82 +	case APP_CMD_SAVE_STATE:
    5.83 +		/* save the application state to be reloaded on restart if needed */
    5.84 +		break;
    5.85 +
    5.86 +	case APP_CMD_INIT_WINDOW:
    5.87 +		if(init_gl() == -1) {
    5.88 +			exit(1);
    5.89 +		}
    5.90 +		/* initialize the application */
    5.91 +		if(init() == -1) {
    5.92 +			exit(1);	/* initialization failed, quit */
    5.93 +		}
    5.94 +		init_done = 1;
    5.95 +		break;
    5.96 +
    5.97 +	case APP_CMD_TERM_WINDOW:
    5.98 +		/* cleanup */
    5.99 +		init_done = 0;
   5.100 +		cleanup();
   5.101 +		destroy_gl();
   5.102 +		break;
   5.103 +
   5.104 +	case APP_CMD_GAINED_FOCUS:
   5.105 +		/* app focused */
   5.106 +		break;
   5.107 +
   5.108 +	case APP_CMD_LOST_FOCUS:
   5.109 +		/* app lost focus */
   5.110 +		break;
   5.111 +
   5.112 +	case APP_CMD_WINDOW_RESIZED:
   5.113 +	case APP_CMD_CONFIG_CHANGED:
   5.114 +		{
   5.115 +			int nx = ANativeWindow_getWidth(app->window);
   5.116 +			int ny = ANativeWindow_getHeight(app->window);
   5.117 +			if(nx != width || ny != height) {
   5.118 +				reshape(nx, ny);
   5.119 +				width = nx;
   5.120 +				height = ny;
   5.121 +			}
   5.122 +		}
   5.123 +		break;
   5.124 +
   5.125 +	default:
   5.126 +		break;
   5.127 +	}
   5.128 +}
   5.129 +
   5.130 +static int handle_input(struct android_app *app, AInputEvent *ev)
   5.131 +{
   5.132 +	int evtype = AInputEvent_getType(ev);
   5.133 +
   5.134 +	switch(evtype) {
   5.135 +	case AINPUT_EVENT_TYPE_MOTION:
   5.136 +		return handle_touch_input(app, ev);
   5.137 +
   5.138 +	default:
   5.139 +		break;
   5.140 +	}
   5.141 +	return 0;
   5.142 +}
   5.143 +
   5.144 +#define MAX_TOUCH_IDS	32
   5.145 +
   5.146 +static int handle_touch_input(struct android_app *app, AInputEvent *ev)
   5.147 +{
   5.148 +	int x, y, idx, touch_id;
   5.149 +	unsigned int action;
   5.150 +	static int prev_pos[MAX_TOUCH_IDS][2];
   5.151 +
   5.152 +	action = AMotionEvent_getAction(ev);
   5.153 +
   5.154 +	idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
   5.155 +		AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   5.156 +	touch_id = AMotionEvent_getPointerId(ev, idx);
   5.157 +
   5.158 +	x = AMotionEvent_getX(ev, idx);
   5.159 +	y = AMotionEvent_getY(ev, idx);
   5.160 +
   5.161 +	switch(action & AMOTION_EVENT_ACTION_MASK) {
   5.162 +	case AMOTION_EVENT_ACTION_DOWN:
   5.163 +	case AMOTION_EVENT_ACTION_POINTER_DOWN:
   5.164 +		if(touch_id == 0) {
   5.165 +			mouse_button(0, 1, x, y);
   5.166 +		}
   5.167 +		if(touch_id < MAX_TOUCH_IDS) {
   5.168 +			prev_pos[touch_id][0] = x;
   5.169 +			prev_pos[touch_id][1] = y;
   5.170 +		}
   5.171 +		break;
   5.172 +
   5.173 +	case AMOTION_EVENT_ACTION_UP:
   5.174 +	case AMOTION_EVENT_ACTION_POINTER_UP:
   5.175 +		if(touch_id == 0) {
   5.176 +			mouse_button(0, 0, x, y);
   5.177 +		}
   5.178 +		if(touch_id < MAX_TOUCH_IDS) {
   5.179 +			prev_pos[touch_id][0] = x;
   5.180 +			prev_pos[touch_id][1] = y;
   5.181 +		}
   5.182 +		break;
   5.183 +
   5.184 +	case AMOTION_EVENT_ACTION_MOVE:
   5.185 +		{
   5.186 +			int i, pcount = AMotionEvent_getPointerCount(ev);
   5.187 +			for(i=0; i<pcount; i++) {
   5.188 +				int id = AMotionEvent_getPointerId(ev, i);
   5.189 +				if(id < MAX_TOUCH_IDS && x != prev_pos[id][0] && y != prev_pos[id][1]) {
   5.190 +					if(id == 0) {
   5.191 +						mouse_motion(x, y);
   5.192 +					}
   5.193 +					prev_pos[id][0] = x;
   5.194 +					prev_pos[id][1] = y;
   5.195 +				}
   5.196 +			}
   5.197 +		}
   5.198 +		break;
   5.199 +
   5.200 +	default:
   5.201 +		break;
   5.202 +	}
   5.203 +
   5.204 +	return 1;
   5.205 +}
   5.206 +
   5.207 +
   5.208 +static int init_gl(void)
   5.209 +{
   5.210 +	static const int eglattr[] = {
   5.211 +		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
   5.212 +		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
   5.213 +		EGL_RED_SIZE, 5,
   5.214 +		EGL_GREEN_SIZE, 5,
   5.215 +		EGL_BLUE_SIZE, 5,
   5.216 +		EGL_DEPTH_SIZE, 16,
   5.217 +		EGL_NONE
   5.218 +	};
   5.219 +	static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
   5.220 +
   5.221 +	EGLConfig eglcfg;
   5.222 +	int count, vis;
   5.223 +
   5.224 +	dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   5.225 +	if(!dpy || !eglInitialize(dpy, 0, 0)) {
   5.226 +		fprintf(stderr, "failed to initialize EGL\n");
   5.227 +		destroy_gl();
   5.228 +		return -1;
   5.229 +	}
   5.230 +
   5.231 +	if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) {
   5.232 +		fprintf(stderr, "no matching EGL config found\n");
   5.233 +		destroy_gl();
   5.234 +		return -1;
   5.235 +	}
   5.236 +
   5.237 +	/* configure the native window visual according to the chosen EGL config */
   5.238 +	eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis);
   5.239 +	ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis);
   5.240 +
   5.241 +	if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) {
   5.242 +		fprintf(stderr, "failed to create window\n");
   5.243 +		destroy_gl();
   5.244 +		return -1;
   5.245 +	}
   5.246 +
   5.247 +	if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) {
   5.248 +		fprintf(stderr, "failed to create OpenGL ES context\n");
   5.249 +		destroy_gl();
   5.250 +		return -1;
   5.251 +	}
   5.252 +	eglMakeCurrent(dpy, surf, surf, ctx);
   5.253 +
   5.254 +	eglQuerySurface(dpy, surf, EGL_WIDTH, &width);
   5.255 +	eglQuerySurface(dpy, surf, EGL_HEIGHT, &height);
   5.256 +	reshape(width, height);
   5.257 +
   5.258 +	return 0;
   5.259 +}
   5.260 +
   5.261 +static void destroy_gl(void)
   5.262 +{
   5.263 +	if(!dpy) return;
   5.264 +
   5.265 +	eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   5.266 +
   5.267 +	if(ctx) {
   5.268 +		eglDestroyContext(dpy, ctx);
   5.269 +		ctx = 0;
   5.270 +	}
   5.271 +	if(surf) {
   5.272 +		eglDestroySurface(dpy, surf);
   5.273 +		surf = 0;
   5.274 +	}
   5.275 +
   5.276 +	eglTerminate(dpy);
   5.277 +	dpy = 0;
   5.278 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/android/android_native_app_glue.c	Sat Oct 03 06:10:30 2015 +0300
     6.3 @@ -0,0 +1,440 @@
     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 +#include <jni.h>
    6.22 +
    6.23 +#include <errno.h>
    6.24 +#include <string.h>
    6.25 +#include <unistd.h>
    6.26 +#include <sys/resource.h>
    6.27 +
    6.28 +#include "android_native_app_glue.h"
    6.29 +#include <android/log.h>
    6.30 +
    6.31 +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
    6.32 +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
    6.33 +
    6.34 +/* For debug builds, always enable the debug traces in this library */
    6.35 +#ifndef NDEBUG
    6.36 +#  define LOGV(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
    6.37 +#else
    6.38 +#  define LOGV(...)  ((void)0)
    6.39 +#endif
    6.40 +
    6.41 +static void free_saved_state(struct android_app* android_app) {
    6.42 +    pthread_mutex_lock(&android_app->mutex);
    6.43 +    if (android_app->savedState != NULL) {
    6.44 +        free(android_app->savedState);
    6.45 +        android_app->savedState = NULL;
    6.46 +        android_app->savedStateSize = 0;
    6.47 +    }
    6.48 +    pthread_mutex_unlock(&android_app->mutex);
    6.49 +}
    6.50 +
    6.51 +int8_t android_app_read_cmd(struct android_app* android_app) {
    6.52 +    int8_t cmd;
    6.53 +    if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
    6.54 +        switch (cmd) {
    6.55 +            case APP_CMD_SAVE_STATE:
    6.56 +                free_saved_state(android_app);
    6.57 +                break;
    6.58 +        }
    6.59 +        return cmd;
    6.60 +    } else {
    6.61 +        LOGE("No data on command pipe!");
    6.62 +    }
    6.63 +    return -1;
    6.64 +}
    6.65 +
    6.66 +static void print_cur_config(struct android_app* android_app) {
    6.67 +    char lang[2], country[2];
    6.68 +    AConfiguration_getLanguage(android_app->config, lang);
    6.69 +    AConfiguration_getCountry(android_app->config, country);
    6.70 +
    6.71 +    LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
    6.72 +            "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
    6.73 +            "modetype=%d modenight=%d",
    6.74 +            AConfiguration_getMcc(android_app->config),
    6.75 +            AConfiguration_getMnc(android_app->config),
    6.76 +            lang[0], lang[1], country[0], country[1],
    6.77 +            AConfiguration_getOrientation(android_app->config),
    6.78 +            AConfiguration_getTouchscreen(android_app->config),
    6.79 +            AConfiguration_getDensity(android_app->config),
    6.80 +            AConfiguration_getKeyboard(android_app->config),
    6.81 +            AConfiguration_getNavigation(android_app->config),
    6.82 +            AConfiguration_getKeysHidden(android_app->config),
    6.83 +            AConfiguration_getNavHidden(android_app->config),
    6.84 +            AConfiguration_getSdkVersion(android_app->config),
    6.85 +            AConfiguration_getScreenSize(android_app->config),
    6.86 +            AConfiguration_getScreenLong(android_app->config),
    6.87 +            AConfiguration_getUiModeType(android_app->config),
    6.88 +            AConfiguration_getUiModeNight(android_app->config));
    6.89 +}
    6.90 +
    6.91 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
    6.92 +    switch (cmd) {
    6.93 +        case APP_CMD_INPUT_CHANGED:
    6.94 +            LOGV("APP_CMD_INPUT_CHANGED\n");
    6.95 +            pthread_mutex_lock(&android_app->mutex);
    6.96 +            if (android_app->inputQueue != NULL) {
    6.97 +                AInputQueue_detachLooper(android_app->inputQueue);
    6.98 +            }
    6.99 +            android_app->inputQueue = android_app->pendingInputQueue;
   6.100 +            if (android_app->inputQueue != NULL) {
   6.101 +                LOGV("Attaching input queue to looper");
   6.102 +                AInputQueue_attachLooper(android_app->inputQueue,
   6.103 +                        android_app->looper, LOOPER_ID_INPUT, NULL,
   6.104 +                        &android_app->inputPollSource);
   6.105 +            }
   6.106 +            pthread_cond_broadcast(&android_app->cond);
   6.107 +            pthread_mutex_unlock(&android_app->mutex);
   6.108 +            break;
   6.109 +
   6.110 +        case APP_CMD_INIT_WINDOW:
   6.111 +            LOGV("APP_CMD_INIT_WINDOW\n");
   6.112 +            pthread_mutex_lock(&android_app->mutex);
   6.113 +            android_app->window = android_app->pendingWindow;
   6.114 +            pthread_cond_broadcast(&android_app->cond);
   6.115 +            pthread_mutex_unlock(&android_app->mutex);
   6.116 +            break;
   6.117 +
   6.118 +        case APP_CMD_TERM_WINDOW:
   6.119 +            LOGV("APP_CMD_TERM_WINDOW\n");
   6.120 +            pthread_cond_broadcast(&android_app->cond);
   6.121 +            break;
   6.122 +
   6.123 +        case APP_CMD_RESUME:
   6.124 +        case APP_CMD_START:
   6.125 +        case APP_CMD_PAUSE:
   6.126 +        case APP_CMD_STOP:
   6.127 +            LOGV("activityState=%d\n", cmd);
   6.128 +            pthread_mutex_lock(&android_app->mutex);
   6.129 +            android_app->activityState = cmd;
   6.130 +            pthread_cond_broadcast(&android_app->cond);
   6.131 +            pthread_mutex_unlock(&android_app->mutex);
   6.132 +            break;
   6.133 +
   6.134 +        case APP_CMD_CONFIG_CHANGED:
   6.135 +            LOGV("APP_CMD_CONFIG_CHANGED\n");
   6.136 +            AConfiguration_fromAssetManager(android_app->config,
   6.137 +                    android_app->activity->assetManager);
   6.138 +            print_cur_config(android_app);
   6.139 +            break;
   6.140 +
   6.141 +        case APP_CMD_DESTROY:
   6.142 +            LOGV("APP_CMD_DESTROY\n");
   6.143 +            android_app->destroyRequested = 1;
   6.144 +            break;
   6.145 +    }
   6.146 +}
   6.147 +
   6.148 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
   6.149 +    switch (cmd) {
   6.150 +        case APP_CMD_TERM_WINDOW:
   6.151 +            LOGV("APP_CMD_TERM_WINDOW\n");
   6.152 +            pthread_mutex_lock(&android_app->mutex);
   6.153 +            android_app->window = NULL;
   6.154 +            pthread_cond_broadcast(&android_app->cond);
   6.155 +            pthread_mutex_unlock(&android_app->mutex);
   6.156 +            break;
   6.157 +
   6.158 +        case APP_CMD_SAVE_STATE:
   6.159 +            LOGV("APP_CMD_SAVE_STATE\n");
   6.160 +            pthread_mutex_lock(&android_app->mutex);
   6.161 +            android_app->stateSaved = 1;
   6.162 +            pthread_cond_broadcast(&android_app->cond);
   6.163 +            pthread_mutex_unlock(&android_app->mutex);
   6.164 +            break;
   6.165 +
   6.166 +        case APP_CMD_RESUME:
   6.167 +            free_saved_state(android_app);
   6.168 +            break;
   6.169 +    }
   6.170 +}
   6.171 +
   6.172 +void app_dummy() {
   6.173 +
   6.174 +}
   6.175 +
   6.176 +static void android_app_destroy(struct android_app* android_app) {
   6.177 +    LOGV("android_app_destroy!");
   6.178 +    free_saved_state(android_app);
   6.179 +    pthread_mutex_lock(&android_app->mutex);
   6.180 +    if (android_app->inputQueue != NULL) {
   6.181 +        AInputQueue_detachLooper(android_app->inputQueue);
   6.182 +    }
   6.183 +    AConfiguration_delete(android_app->config);
   6.184 +    android_app->destroyed = 1;
   6.185 +    pthread_cond_broadcast(&android_app->cond);
   6.186 +    pthread_mutex_unlock(&android_app->mutex);
   6.187 +    // Can't touch android_app object after this.
   6.188 +}
   6.189 +
   6.190 +static void process_input(struct android_app* app, struct android_poll_source* source) {
   6.191 +    AInputEvent* event = NULL;
   6.192 +    while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
   6.193 +        LOGV("New input event: type=%d\n", AInputEvent_getType(event));
   6.194 +        if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
   6.195 +            continue;
   6.196 +        }
   6.197 +        int32_t handled = 0;
   6.198 +        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
   6.199 +        AInputQueue_finishEvent(app->inputQueue, event, handled);
   6.200 +    }
   6.201 +}
   6.202 +
   6.203 +static void process_cmd(struct android_app* app, struct android_poll_source* source) {
   6.204 +    int8_t cmd = android_app_read_cmd(app);
   6.205 +    android_app_pre_exec_cmd(app, cmd);
   6.206 +    if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
   6.207 +    android_app_post_exec_cmd(app, cmd);
   6.208 +}
   6.209 +
   6.210 +static void* android_app_entry(void* param) {
   6.211 +    struct android_app* android_app = (struct android_app*)param;
   6.212 +
   6.213 +    android_app->config = AConfiguration_new();
   6.214 +    AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
   6.215 +
   6.216 +    print_cur_config(android_app);
   6.217 +
   6.218 +    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
   6.219 +    android_app->cmdPollSource.app = android_app;
   6.220 +    android_app->cmdPollSource.process = process_cmd;
   6.221 +    android_app->inputPollSource.id = LOOPER_ID_INPUT;
   6.222 +    android_app->inputPollSource.app = android_app;
   6.223 +    android_app->inputPollSource.process = process_input;
   6.224 +
   6.225 +    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
   6.226 +    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
   6.227 +            &android_app->cmdPollSource);
   6.228 +    android_app->looper = looper;
   6.229 +
   6.230 +    pthread_mutex_lock(&android_app->mutex);
   6.231 +    android_app->running = 1;
   6.232 +    pthread_cond_broadcast(&android_app->cond);
   6.233 +    pthread_mutex_unlock(&android_app->mutex);
   6.234 +
   6.235 +    android_main(android_app);
   6.236 +
   6.237 +    android_app_destroy(android_app);
   6.238 +    return NULL;
   6.239 +}
   6.240 +
   6.241 +// --------------------------------------------------------------------
   6.242 +// Native activity interaction (called from main thread)
   6.243 +// --------------------------------------------------------------------
   6.244 +
   6.245 +static struct android_app* android_app_create(ANativeActivity* activity,
   6.246 +        void* savedState, size_t savedStateSize) {
   6.247 +    struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
   6.248 +    memset(android_app, 0, sizeof(struct android_app));
   6.249 +    android_app->activity = activity;
   6.250 +
   6.251 +    pthread_mutex_init(&android_app->mutex, NULL);
   6.252 +    pthread_cond_init(&android_app->cond, NULL);
   6.253 +
   6.254 +    if (savedState != NULL) {
   6.255 +        android_app->savedState = malloc(savedStateSize);
   6.256 +        android_app->savedStateSize = savedStateSize;
   6.257 +        memcpy(android_app->savedState, savedState, savedStateSize);
   6.258 +    }
   6.259 +
   6.260 +    int msgpipe[2];
   6.261 +    if (pipe(msgpipe)) {
   6.262 +        LOGE("could not create pipe: %s", strerror(errno));
   6.263 +        return NULL;
   6.264 +    }
   6.265 +    android_app->msgread = msgpipe[0];
   6.266 +    android_app->msgwrite = msgpipe[1];
   6.267 +
   6.268 +    pthread_attr_t attr; 
   6.269 +    pthread_attr_init(&attr);
   6.270 +    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   6.271 +    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
   6.272 +
   6.273 +    // Wait for thread to start.
   6.274 +    pthread_mutex_lock(&android_app->mutex);
   6.275 +    while (!android_app->running) {
   6.276 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.277 +    }
   6.278 +    pthread_mutex_unlock(&android_app->mutex);
   6.279 +
   6.280 +    return android_app;
   6.281 +}
   6.282 +
   6.283 +static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
   6.284 +    if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
   6.285 +        LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
   6.286 +    }
   6.287 +}
   6.288 +
   6.289 +static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
   6.290 +    pthread_mutex_lock(&android_app->mutex);
   6.291 +    android_app->pendingInputQueue = inputQueue;
   6.292 +    android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
   6.293 +    while (android_app->inputQueue != android_app->pendingInputQueue) {
   6.294 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.295 +    }
   6.296 +    pthread_mutex_unlock(&android_app->mutex);
   6.297 +}
   6.298 +
   6.299 +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
   6.300 +    pthread_mutex_lock(&android_app->mutex);
   6.301 +    if (android_app->pendingWindow != NULL) {
   6.302 +        android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
   6.303 +    }
   6.304 +    android_app->pendingWindow = window;
   6.305 +    if (window != NULL) {
   6.306 +        android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
   6.307 +    }
   6.308 +    while (android_app->window != android_app->pendingWindow) {
   6.309 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.310 +    }
   6.311 +    pthread_mutex_unlock(&android_app->mutex);
   6.312 +}
   6.313 +
   6.314 +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
   6.315 +    pthread_mutex_lock(&android_app->mutex);
   6.316 +    android_app_write_cmd(android_app, cmd);
   6.317 +    while (android_app->activityState != cmd) {
   6.318 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.319 +    }
   6.320 +    pthread_mutex_unlock(&android_app->mutex);
   6.321 +}
   6.322 +
   6.323 +static void android_app_free(struct android_app* android_app) {
   6.324 +    pthread_mutex_lock(&android_app->mutex);
   6.325 +    android_app_write_cmd(android_app, APP_CMD_DESTROY);
   6.326 +    while (!android_app->destroyed) {
   6.327 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.328 +    }
   6.329 +    pthread_mutex_unlock(&android_app->mutex);
   6.330 +
   6.331 +    close(android_app->msgread);
   6.332 +    close(android_app->msgwrite);
   6.333 +    pthread_cond_destroy(&android_app->cond);
   6.334 +    pthread_mutex_destroy(&android_app->mutex);
   6.335 +    free(android_app);
   6.336 +}
   6.337 +
   6.338 +static void onDestroy(ANativeActivity* activity) {
   6.339 +    LOGV("Destroy: %p\n", activity);
   6.340 +    android_app_free((struct android_app*)activity->instance);
   6.341 +}
   6.342 +
   6.343 +static void onStart(ANativeActivity* activity) {
   6.344 +    LOGV("Start: %p\n", activity);
   6.345 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
   6.346 +}
   6.347 +
   6.348 +static void onResume(ANativeActivity* activity) {
   6.349 +    LOGV("Resume: %p\n", activity);
   6.350 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
   6.351 +}
   6.352 +
   6.353 +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
   6.354 +    struct android_app* android_app = (struct android_app*)activity->instance;
   6.355 +    void* savedState = NULL;
   6.356 +
   6.357 +    LOGV("SaveInstanceState: %p\n", activity);
   6.358 +    pthread_mutex_lock(&android_app->mutex);
   6.359 +    android_app->stateSaved = 0;
   6.360 +    android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
   6.361 +    while (!android_app->stateSaved) {
   6.362 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   6.363 +    }
   6.364 +
   6.365 +    if (android_app->savedState != NULL) {
   6.366 +        savedState = android_app->savedState;
   6.367 +        *outLen = android_app->savedStateSize;
   6.368 +        android_app->savedState = NULL;
   6.369 +        android_app->savedStateSize = 0;
   6.370 +    }
   6.371 +
   6.372 +    pthread_mutex_unlock(&android_app->mutex);
   6.373 +
   6.374 +    return savedState;
   6.375 +}
   6.376 +
   6.377 +static void onPause(ANativeActivity* activity) {
   6.378 +    LOGV("Pause: %p\n", activity);
   6.379 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
   6.380 +}
   6.381 +
   6.382 +static void onStop(ANativeActivity* activity) {
   6.383 +    LOGV("Stop: %p\n", activity);
   6.384 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
   6.385 +}
   6.386 +
   6.387 +static void onConfigurationChanged(ANativeActivity* activity) {
   6.388 +    struct android_app* android_app = (struct android_app*)activity->instance;
   6.389 +    LOGV("ConfigurationChanged: %p\n", activity);
   6.390 +    android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
   6.391 +}
   6.392 +
   6.393 +static void onLowMemory(ANativeActivity* activity) {
   6.394 +    struct android_app* android_app = (struct android_app*)activity->instance;
   6.395 +    LOGV("LowMemory: %p\n", activity);
   6.396 +    android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
   6.397 +}
   6.398 +
   6.399 +static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
   6.400 +    LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
   6.401 +    android_app_write_cmd((struct android_app*)activity->instance,
   6.402 +            focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
   6.403 +}
   6.404 +
   6.405 +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
   6.406 +    LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
   6.407 +    android_app_set_window((struct android_app*)activity->instance, window);
   6.408 +}
   6.409 +
   6.410 +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
   6.411 +    LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
   6.412 +    android_app_set_window((struct android_app*)activity->instance, NULL);
   6.413 +}
   6.414 +
   6.415 +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
   6.416 +    LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
   6.417 +    android_app_set_input((struct android_app*)activity->instance, queue);
   6.418 +}
   6.419 +
   6.420 +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
   6.421 +    LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
   6.422 +    android_app_set_input((struct android_app*)activity->instance, NULL);
   6.423 +}
   6.424 +
   6.425 +void ANativeActivity_onCreate(ANativeActivity* activity,
   6.426 +        void* savedState, size_t savedStateSize) {
   6.427 +    LOGV("Creating: %p\n", activity);
   6.428 +    activity->callbacks->onDestroy = onDestroy;
   6.429 +    activity->callbacks->onStart = onStart;
   6.430 +    activity->callbacks->onResume = onResume;
   6.431 +    activity->callbacks->onSaveInstanceState = onSaveInstanceState;
   6.432 +    activity->callbacks->onPause = onPause;
   6.433 +    activity->callbacks->onStop = onStop;
   6.434 +    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
   6.435 +    activity->callbacks->onLowMemory = onLowMemory;
   6.436 +    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
   6.437 +    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
   6.438 +    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
   6.439 +    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
   6.440 +    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
   6.441 +
   6.442 +    activity->instance = android_app_create(activity, savedState, savedStateSize);
   6.443 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/android/android_native_app_glue.h	Sat Oct 03 06:10:30 2015 +0300
     7.3 @@ -0,0 +1,349 @@
     7.4 +/*
     7.5 + * Copyright (C) 2010 The Android Open Source Project
     7.6 + *
     7.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     7.8 + * you may not use this file except in compliance with the License.
     7.9 + * You may obtain a copy of the License at
    7.10 + *
    7.11 + *      http://www.apache.org/licenses/LICENSE-2.0
    7.12 + *
    7.13 + * Unless required by applicable law or agreed to in writing, software
    7.14 + * distributed under the License is distributed on an "AS IS" BASIS,
    7.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    7.16 + * See the License for the specific language governing permissions and
    7.17 + * limitations under the License.
    7.18 + *
    7.19 + */
    7.20 +
    7.21 +#ifndef _ANDROID_NATIVE_APP_GLUE_H
    7.22 +#define _ANDROID_NATIVE_APP_GLUE_H
    7.23 +
    7.24 +#include <poll.h>
    7.25 +#include <pthread.h>
    7.26 +#include <sched.h>
    7.27 +
    7.28 +#include <android/configuration.h>
    7.29 +#include <android/looper.h>
    7.30 +#include <android/native_activity.h>
    7.31 +
    7.32 +#ifdef __cplusplus
    7.33 +extern "C" {
    7.34 +#endif
    7.35 +
    7.36 +/**
    7.37 + * The native activity interface provided by <android/native_activity.h>
    7.38 + * is based on a set of application-provided callbacks that will be called
    7.39 + * by the Activity's main thread when certain events occur.
    7.40 + *
    7.41 + * This means that each one of this callbacks _should_ _not_ block, or they
    7.42 + * risk having the system force-close the application. This programming
    7.43 + * model is direct, lightweight, but constraining.
    7.44 + *
    7.45 + * The 'android_native_app_glue' static library is used to provide a different
    7.46 + * execution model where the application can implement its own main event
    7.47 + * loop in a different thread instead. Here's how it works:
    7.48 + *
    7.49 + * 1/ The application must provide a function named "android_main()" that
    7.50 + *    will be called when the activity is created, in a new thread that is
    7.51 + *    distinct from the activity's main thread.
    7.52 + *
    7.53 + * 2/ android_main() receives a pointer to a valid "android_app" structure
    7.54 + *    that contains references to other important objects, e.g. the
    7.55 + *    ANativeActivity obejct instance the application is running in.
    7.56 + *
    7.57 + * 3/ the "android_app" object holds an ALooper instance that already
    7.58 + *    listens to two important things:
    7.59 + *
    7.60 + *      - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
    7.61 + *        declarations below.
    7.62 + *
    7.63 + *      - input events coming from the AInputQueue attached to the activity.
    7.64 + *
    7.65 + *    Each of these correspond to an ALooper identifier returned by
    7.66 + *    ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
    7.67 + *    respectively.
    7.68 + *
    7.69 + *    Your application can use the same ALooper to listen to additional
    7.70 + *    file-descriptors.  They can either be callback based, or with return
    7.71 + *    identifiers starting with LOOPER_ID_USER.
    7.72 + *
    7.73 + * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
    7.74 + *    the returned data will point to an android_poll_source structure.  You
    7.75 + *    can call the process() function on it, and fill in android_app->onAppCmd
    7.76 + *    and android_app->onInputEvent to be called for your own processing
    7.77 + *    of the event.
    7.78 + *
    7.79 + *    Alternatively, you can call the low-level functions to read and process
    7.80 + *    the data directly...  look at the process_cmd() and process_input()
    7.81 + *    implementations in the glue to see how to do this.
    7.82 + *
    7.83 + * See the sample named "native-activity" that comes with the NDK with a
    7.84 + * full usage example.  Also look at the JavaDoc of NativeActivity.
    7.85 + */
    7.86 +
    7.87 +struct android_app;
    7.88 +
    7.89 +/**
    7.90 + * Data associated with an ALooper fd that will be returned as the "outData"
    7.91 + * when that source has data ready.
    7.92 + */
    7.93 +struct android_poll_source {
    7.94 +    // The identifier of this source.  May be LOOPER_ID_MAIN or
    7.95 +    // LOOPER_ID_INPUT.
    7.96 +    int32_t id;
    7.97 +
    7.98 +    // The android_app this ident is associated with.
    7.99 +    struct android_app* app;
   7.100 +
   7.101 +    // Function to call to perform the standard processing of data from
   7.102 +    // this source.
   7.103 +    void (*process)(struct android_app* app, struct android_poll_source* source);
   7.104 +};
   7.105 +
   7.106 +/**
   7.107 + * This is the interface for the standard glue code of a threaded
   7.108 + * application.  In this model, the application's code is running
   7.109 + * in its own thread separate from the main thread of the process.
   7.110 + * It is not required that this thread be associated with the Java
   7.111 + * VM, although it will need to be in order to make JNI calls any
   7.112 + * Java objects.
   7.113 + */
   7.114 +struct android_app {
   7.115 +    // The application can place a pointer to its own state object
   7.116 +    // here if it likes.
   7.117 +    void* userData;
   7.118 +
   7.119 +    // Fill this in with the function to process main app commands (APP_CMD_*)
   7.120 +    void (*onAppCmd)(struct android_app* app, int32_t cmd);
   7.121 +
   7.122 +    // Fill this in with the function to process input events.  At this point
   7.123 +    // the event has already been pre-dispatched, and it will be finished upon
   7.124 +    // return.  Return 1 if you have handled the event, 0 for any default
   7.125 +    // dispatching.
   7.126 +    int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
   7.127 +
   7.128 +    // The ANativeActivity object instance that this app is running in.
   7.129 +    ANativeActivity* activity;
   7.130 +
   7.131 +    // The current configuration the app is running in.
   7.132 +    AConfiguration* config;
   7.133 +
   7.134 +    // This is the last instance's saved state, as provided at creation time.
   7.135 +    // It is NULL if there was no state.  You can use this as you need; the
   7.136 +    // memory will remain around until you call android_app_exec_cmd() for
   7.137 +    // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
   7.138 +    // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
   7.139 +    // at which point they will be initialized to NULL and you can malloc your
   7.140 +    // state and place the information here.  In that case the memory will be
   7.141 +    // freed for you later.
   7.142 +    void* savedState;
   7.143 +    size_t savedStateSize;
   7.144 +
   7.145 +    // The ALooper associated with the app's thread.
   7.146 +    ALooper* looper;
   7.147 +
   7.148 +    // When non-NULL, this is the input queue from which the app will
   7.149 +    // receive user input events.
   7.150 +    AInputQueue* inputQueue;
   7.151 +
   7.152 +    // When non-NULL, this is the window surface that the app can draw in.
   7.153 +    ANativeWindow* window;
   7.154 +
   7.155 +    // Current content rectangle of the window; this is the area where the
   7.156 +    // window's content should be placed to be seen by the user.
   7.157 +    ARect contentRect;
   7.158 +
   7.159 +    // Current state of the app's activity.  May be either APP_CMD_START,
   7.160 +    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
   7.161 +    int activityState;
   7.162 +
   7.163 +    // This is non-zero when the application's NativeActivity is being
   7.164 +    // destroyed and waiting for the app thread to complete.
   7.165 +    int destroyRequested;
   7.166 +
   7.167 +    // -------------------------------------------------
   7.168 +    // Below are "private" implementation of the glue code.
   7.169 +
   7.170 +    pthread_mutex_t mutex;
   7.171 +    pthread_cond_t cond;
   7.172 +
   7.173 +    int msgread;
   7.174 +    int msgwrite;
   7.175 +
   7.176 +    pthread_t thread;
   7.177 +
   7.178 +    struct android_poll_source cmdPollSource;
   7.179 +    struct android_poll_source inputPollSource;
   7.180 +
   7.181 +    int running;
   7.182 +    int stateSaved;
   7.183 +    int destroyed;
   7.184 +    int redrawNeeded;
   7.185 +    AInputQueue* pendingInputQueue;
   7.186 +    ANativeWindow* pendingWindow;
   7.187 +    ARect pendingContentRect;
   7.188 +};
   7.189 +
   7.190 +enum {
   7.191 +    /**
   7.192 +     * Looper data ID of commands coming from the app's main thread, which
   7.193 +     * is returned as an identifier from ALooper_pollOnce().  The data for this
   7.194 +     * identifier is a pointer to an android_poll_source structure.
   7.195 +     * These can be retrieved and processed with android_app_read_cmd()
   7.196 +     * and android_app_exec_cmd().
   7.197 +     */
   7.198 +    LOOPER_ID_MAIN = 1,
   7.199 +
   7.200 +    /**
   7.201 +     * Looper data ID of events coming from the AInputQueue of the
   7.202 +     * application's window, which is returned as an identifier from
   7.203 +     * ALooper_pollOnce().  The data for this identifier is a pointer to an
   7.204 +     * android_poll_source structure.  These can be read via the inputQueue
   7.205 +     * object of android_app.
   7.206 +     */
   7.207 +    LOOPER_ID_INPUT = 2,
   7.208 +
   7.209 +    /**
   7.210 +     * Start of user-defined ALooper identifiers.
   7.211 +     */
   7.212 +    LOOPER_ID_USER = 3,
   7.213 +};
   7.214 +
   7.215 +enum {
   7.216 +    /**
   7.217 +     * Command from main thread: the AInputQueue has changed.  Upon processing
   7.218 +     * this command, android_app->inputQueue will be updated to the new queue
   7.219 +     * (or NULL).
   7.220 +     */
   7.221 +    APP_CMD_INPUT_CHANGED,
   7.222 +
   7.223 +    /**
   7.224 +     * Command from main thread: a new ANativeWindow is ready for use.  Upon
   7.225 +     * receiving this command, android_app->window will contain the new window
   7.226 +     * surface.
   7.227 +     */
   7.228 +    APP_CMD_INIT_WINDOW,
   7.229 +
   7.230 +    /**
   7.231 +     * Command from main thread: the existing ANativeWindow needs to be
   7.232 +     * terminated.  Upon receiving this command, android_app->window still
   7.233 +     * contains the existing window; after calling android_app_exec_cmd
   7.234 +     * it will be set to NULL.
   7.235 +     */
   7.236 +    APP_CMD_TERM_WINDOW,
   7.237 +
   7.238 +    /**
   7.239 +     * Command from main thread: the current ANativeWindow has been resized.
   7.240 +     * Please redraw with its new size.
   7.241 +     */
   7.242 +    APP_CMD_WINDOW_RESIZED,
   7.243 +
   7.244 +    /**
   7.245 +     * Command from main thread: the system needs that the current ANativeWindow
   7.246 +     * be redrawn.  You should redraw the window before handing this to
   7.247 +     * android_app_exec_cmd() in order to avoid transient drawing glitches.
   7.248 +     */
   7.249 +    APP_CMD_WINDOW_REDRAW_NEEDED,
   7.250 +
   7.251 +    /**
   7.252 +     * Command from main thread: the content area of the window has changed,
   7.253 +     * such as from the soft input window being shown or hidden.  You can
   7.254 +     * find the new content rect in android_app::contentRect.
   7.255 +     */
   7.256 +    APP_CMD_CONTENT_RECT_CHANGED,
   7.257 +
   7.258 +    /**
   7.259 +     * Command from main thread: the app's activity window has gained
   7.260 +     * input focus.
   7.261 +     */
   7.262 +    APP_CMD_GAINED_FOCUS,
   7.263 +
   7.264 +    /**
   7.265 +     * Command from main thread: the app's activity window has lost
   7.266 +     * input focus.
   7.267 +     */
   7.268 +    APP_CMD_LOST_FOCUS,
   7.269 +
   7.270 +    /**
   7.271 +     * Command from main thread: the current device configuration has changed.
   7.272 +     */
   7.273 +    APP_CMD_CONFIG_CHANGED,
   7.274 +
   7.275 +    /**
   7.276 +     * Command from main thread: the system is running low on memory.
   7.277 +     * Try to reduce your memory use.
   7.278 +     */
   7.279 +    APP_CMD_LOW_MEMORY,
   7.280 +
   7.281 +    /**
   7.282 +     * Command from main thread: the app's activity has been started.
   7.283 +     */
   7.284 +    APP_CMD_START,
   7.285 +
   7.286 +    /**
   7.287 +     * Command from main thread: the app's activity has been resumed.
   7.288 +     */
   7.289 +    APP_CMD_RESUME,
   7.290 +
   7.291 +    /**
   7.292 +     * Command from main thread: the app should generate a new saved state
   7.293 +     * for itself, to restore from later if needed.  If you have saved state,
   7.294 +     * allocate it with malloc and place it in android_app.savedState with
   7.295 +     * the size in android_app.savedStateSize.  The will be freed for you
   7.296 +     * later.
   7.297 +     */
   7.298 +    APP_CMD_SAVE_STATE,
   7.299 +
   7.300 +    /**
   7.301 +     * Command from main thread: the app's activity has been paused.
   7.302 +     */
   7.303 +    APP_CMD_PAUSE,
   7.304 +
   7.305 +    /**
   7.306 +     * Command from main thread: the app's activity has been stopped.
   7.307 +     */
   7.308 +    APP_CMD_STOP,
   7.309 +
   7.310 +    /**
   7.311 +     * Command from main thread: the app's activity is being destroyed,
   7.312 +     * and waiting for the app thread to clean up and exit before proceeding.
   7.313 +     */
   7.314 +    APP_CMD_DESTROY,
   7.315 +};
   7.316 +
   7.317 +/**
   7.318 + * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
   7.319 + * app command message.
   7.320 + */
   7.321 +int8_t android_app_read_cmd(struct android_app* android_app);
   7.322 +
   7.323 +/**
   7.324 + * Call with the command returned by android_app_read_cmd() to do the
   7.325 + * initial pre-processing of the given command.  You can perform your own
   7.326 + * actions for the command after calling this function.
   7.327 + */
   7.328 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
   7.329 +
   7.330 +/**
   7.331 + * Call with the command returned by android_app_read_cmd() to do the
   7.332 + * final post-processing of the given command.  You must have done your own
   7.333 + * actions for the command before calling this function.
   7.334 + */
   7.335 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
   7.336 +
   7.337 +/**
   7.338 + * Dummy function you can call to ensure glue code isn't stripped.
   7.339 + */
   7.340 +void app_dummy();
   7.341 +
   7.342 +/**
   7.343 + * This is the function that application code must implement, representing
   7.344 + * the main entry to the app.
   7.345 + */
   7.346 +extern void android_main(struct android_app* app);
   7.347 +
   7.348 +#ifdef __cplusplus
   7.349 +}
   7.350 +#endif
   7.351 +
   7.352 +#endif /* _ANDROID_NATIVE_APP_GLUE_H */
     8.1 --- a/src/android/assman.c	Fri Oct 02 07:10:19 2015 +0300
     8.2 +++ b/src/android/assman.c	Sat Oct 03 06:10:30 2015 +0300
     8.3 @@ -1,8 +1,9 @@
     8.4  #include <fcntl.h>
     8.5  #include <android/asset_manager.h>
     8.6  #include "assman.h"
     8.7 -#include "native_glue.h"
     8.8 -#include "amain.h"
     8.9 +#include "android_native_app_glue.h"
    8.10 +
    8.11 +struct android_app *app;	/* defined in android/amain.c */
    8.12  
    8.13  ass_file *ass_fopen(const char *fname, const char *mode)
    8.14  {
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/android/logger.c	Sat Oct 03 06:10:30 2015 +0300
     9.3 @@ -0,0 +1,60 @@
     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 +
    9.11 +static void *thread_func(void *arg);
    9.12 +
    9.13 +static int pfd[2];
    9.14 +static pthread_t thr;
    9.15 +static int initialized;
    9.16 +
    9.17 +int start_logger(void)
    9.18 +{
    9.19 +	if(initialized) {
    9.20 +		return 1;
    9.21 +	}
    9.22 +
    9.23 +	/* set stdout to line-buffered, and stderr to unbuffered */
    9.24 +	setvbuf(stdout, 0, _IOLBF, 0);
    9.25 +	setvbuf(stderr, 0, _IONBF, 0);
    9.26 +
    9.27 +	if(pipe(pfd) == -1) {
    9.28 +		perror("failed to create logging pipe");
    9.29 +		return -1;
    9.30 +	}
    9.31 +	assert(pfd[0] > 2 && pfd[1] > 2);
    9.32 +
    9.33 +	/* redirect stdout & stderr to the write-end of the pipe */
    9.34 +	dup2(pfd[1], 1);
    9.35 +	dup2(pfd[1], 2);
    9.36 +
    9.37 +	/* start the logging thread */
    9.38 +	if(pthread_create(&thr, 0, thread_func, 0) == -1) {
    9.39 +		perror("failed to spawn logging thread");
    9.40 +		return -1;
    9.41 +	}
    9.42 +	pthread_detach(thr);
    9.43 +	return 0;
    9.44 +}
    9.45 +
    9.46 +static void *thread_func(void *arg)
    9.47 +{
    9.48 +	ssize_t rdsz;
    9.49 +	char buf[257];
    9.50 +
    9.51 +	__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger starting up...");
    9.52 +
    9.53 +	while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
    9.54 +		if(buf[rdsz - 1] == '\n') {
    9.55 +			--rdsz;
    9.56 +		}
    9.57 +		buf[rdsz] = 0;
    9.58 +		__android_log_write(ANDROID_LOG_DEBUG, APP_NAME, buf);
    9.59 +	}
    9.60 +
    9.61 +	__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger shutting down...");
    9.62 +	return 0;
    9.63 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/android/logger.h	Sat Oct 03 06:10:30 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 --- a/src/opengl.h	Fri Oct 02 07:10:19 2015 +0300
    11.2 +++ b/src/opengl.h	Sat Oct 03 06:10:30 2015 +0300
    11.3 @@ -1,6 +1,6 @@
    11.4  /*
    11.5  Stereoscopic tunnel for iOS.
    11.6 -Copyright (C) 2011  John Tsiombikas <nuclear@member.fsf.org>
    11.7 +Copyright (C) 2011-2015 John Tsiombikas <nuclear@member.fsf.org>
    11.8  
    11.9  This program is free software: you can redistribute it and/or modify
   11.10  it under the terms of the GNU General Public License as published by
   11.11 @@ -28,6 +28,13 @@
   11.12  #define glClearDepth	glClearDepthf
   11.13  #define GLDEF
   11.14  #include "sanegl.h"
   11.15 +
   11.16 +#elif defined(ANDROID)
   11.17 +#include <GLES2/gl2.h>
   11.18 +#include <GLES2/gl2ext.h>
   11.19 +#define GLDEF
   11.20 +#include "sanegl.h"
   11.21 +
   11.22  #else
   11.23  
   11.24  #include <GL/glew.h>