8 #include <android/window.h>
9 #include "android_native_app_glue.h"
13 static void handle_command(struct android_app *app, int32_t cmd);
14 static int handle_input(struct android_app *app, AInputEvent *ev);
15 static int handle_touch_input(struct android_app *app, AInputEvent *ev);
16 static int init_gl(void);
17 static void destroy_gl(void);
18 static unsigned long get_time_msec(void);
19 static void hide_navbar(struct android_app *state);
20 static const char *cmdname(uint32_t cmd);
22 struct android_app *app;
24 static EGLDisplay dpy;
25 static EGLSurface surf;
26 static EGLContext ctx;
27 static int init_done, paused, win_valid;
29 static int width, height;
31 static long init_time;
34 void android_main(struct android_app *app_ptr)
38 app->onAppCmd = handle_command;
39 app->onInputEvent = handle_input;
45 printf("Running %d bit version\n", (int)sizeof(void*) << 3);
47 load_config("demo.cfg");
51 struct android_poll_source *pollsrc;
53 while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) {
55 pollsrc->process(app, pollsrc);
59 if(app->destroyRequested) {
63 sys_time = (long)get_time_msec();
65 if(win_valid && sys_time - init_time >= 700) {
66 if(demo_init() == -1) {
69 demo_reshape(width, height);
76 eglSwapBuffers(dpy, surf);
82 void swap_buffers(void)
84 eglSwapBuffers(dpy, surf);
87 static void handle_command(struct android_app *app, int32_t cmd)
91 printf("DBG android command: %s\n", cmdname(cmd));
95 paused = 1; /* TODO: handle timers */
101 case APP_CMD_INIT_WINDOW:
102 ANativeActivity_setWindowFlags(app->activity, AWINDOW_FLAG_KEEP_SCREEN_ON, 0);
103 if(init_gl() == -1) {
106 init_time = (long)get_time_msec();
110 case APP_CMD_TERM_WINDOW:
119 case APP_CMD_WINDOW_RESIZED:
120 case APP_CMD_CONFIG_CHANGED:
121 xsz = ANativeWindow_getWidth(app->window);
122 ysz = ANativeWindow_getHeight(app->window);
123 if(xsz != width || ysz != height) {
124 printf("reshape(%d, %d)\n", xsz, ysz);
125 demo_reshape(xsz, ysz);
132 case APP_CMD_SAVE_STATE:
133 case APP_CMD_GAINED_FOCUS:
134 case APP_CMD_LOST_FOCUS:
141 static int handle_input(struct android_app *app, AInputEvent *ev)
143 int evtype = AInputEvent_getType(ev);
146 case AINPUT_EVENT_TYPE_MOTION:
147 return handle_touch_input(app, ev);
155 static int handle_touch_input(struct android_app *app, AInputEvent *ev)
157 int i, pcount, x, y, idx;
159 static int prev_pos[2];
161 action = AMotionEvent_getAction(ev);
163 idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
164 AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
166 x = AMotionEvent_getX(ev, idx);
167 y = AMotionEvent_getY(ev, idx);
169 switch(action & AMOTION_EVENT_ACTION_MASK) {
170 case AMOTION_EVENT_ACTION_DOWN:
171 case AMOTION_EVENT_ACTION_POINTER_DOWN:
172 demo_mouse(0, 1, x, y);
178 case AMOTION_EVENT_ACTION_UP:
179 case AMOTION_EVENT_ACTION_POINTER_UP:
180 demo_mouse(0, 0, x, y);
186 case AMOTION_EVENT_ACTION_MOVE:
187 pcount = AMotionEvent_getPointerCount(ev);
188 for(i=0; i<pcount; i++) {
189 int id = AMotionEvent_getPointerId(ev, i);
206 static int init_gl(void)
208 static const int eglattr[] = {
209 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
210 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
217 static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
222 dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
223 if(!dpy || !eglInitialize(dpy, 0, 0)) {
224 fprintf(stderr, "failed to initialize EGL\n");
229 if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) {
230 fprintf(stderr, "no matching EGL config found\n");
235 /* configure the native window visual according to the chosen EGL config */
236 eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis);
237 ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis);
239 if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) {
240 fprintf(stderr, "failed to create window\n");
245 if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) {
246 fprintf(stderr, "failed to create OpenGL ES context\n");
250 eglMakeCurrent(dpy, surf, surf, ctx);
252 eglQuerySurface(dpy, surf, EGL_WIDTH, &width);
253 eglQuerySurface(dpy, surf, EGL_HEIGHT, &height);
257 static void destroy_gl(void)
261 eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
264 eglDestroyContext(dpy, ctx);
268 eglDestroySurface(dpy, surf);
276 static unsigned long get_time_msec(void)
279 static struct timespec ts0;
281 clock_gettime(CLOCK_MONOTONIC, &ts);
282 if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) {
286 return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000;
289 static void hide_navbar(struct android_app *state)
292 jclass cactivity, cwin, cview;
294 jmethodID get_window, get_decor_view, set_system_ui_visibility;
295 jfieldID field_flag_fs, field_flag_hidenav, field_flag_immersive;
296 int flag_fs, flag_hidenav, flag_immersive;
298 (*state->activity->vm)->AttachCurrentThread(state->activity->vm, &env, 0);
300 cactivity = (*env)->FindClass(env, "android/app/NativeActivity");
301 get_window = (*env)->GetMethodID(env, cactivity, "getWindow", "()Landroid/view/Window;");
303 cwin = (*env)->FindClass(env, "android/view/Window");
304 get_decor_view = (*env)->GetMethodID(env, cwin, "getDecorView", "()Landroid/view/View;");
306 cview = (*env)->FindClass(env, "android/view/View");
307 set_system_ui_visibility = (*env)->GetMethodID(env, cview, "setSystemUiVisibility", "(I)V");
309 win = (*env)->CallObjectMethod(env, state->activity->clazz, get_window);
310 view = (*env)->CallObjectMethod(env, win, get_decor_view);
312 field_flag_fs = (*env)->GetStaticFieldID(env, cview, "SYSTEM_UI_FLAG_FULLSCREEN", "I");
313 field_flag_hidenav = (*env)->GetStaticFieldID(env, cview, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I");
314 field_flag_immersive = (*env)->GetStaticFieldID(env, cview, "SYSTEM_UI_FLAG_IMMERSIVE_STICKY", "I");
316 flag_fs = (*env)->GetStaticIntField(env, cview, field_flag_fs);
317 flag_hidenav = (*env)->GetStaticIntField(env, cview, field_flag_hidenav);
318 flag_immersive = (*env)->GetStaticIntField(env, cview, field_flag_immersive);
320 (*env)->CallVoidMethod(env, view, set_system_ui_visibility, flag_fs | flag_hidenav | flag_immersive);
322 (*state->activity->vm)->DetachCurrentThread(state->activity->vm);
325 static const char *cmdname(uint32_t cmd)
327 static const char *names[] = {
328 "APP_CMD_INPUT_CHANGED",
329 "APP_CMD_INIT_WINDOW",
330 "APP_CMD_TERM_WINDOW",
331 "APP_CMD_WINDOW_RESIZED",
332 "APP_CMD_WINDOW_REDRAW_NEEDED",
333 "APP_CMD_CONTENT_RECT_CHANGED",
334 "APP_CMD_GAINED_FOCUS",
335 "APP_CMD_LOST_FOCUS",
336 "APP_CMD_CONFIG_CHANGED",
337 "APP_CMD_LOW_MEMORY",
340 "APP_CMD_SAVE_STATE",
345 if(cmd >= sizeof names / sizeof *names) {