1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * Android Java/JNI system driver
12 *
13 * By Thomas Fjellstrom.
14 *
15 */
16
17 #include "allegro5/allegro.h"
18 #include "allegro5/allegro_android.h"
19 #include "allegro5/platform/aintunix.h"
20 #include "allegro5/internal/aintern_android.h"
21 #include "allegro5/internal/aintern_tls.h"
22 #include "allegro5/platform/aintandroid.h"
23 #include "allegro5/platform/alandroid.h"
24 #include "allegro5/threads.h"
25
26 #include <dlfcn.h>
27 #include <jni.h>
28
29 #include "allegro5/allegro_opengl.h"
30 #include "allegro5/internal/aintern_opengl.h"
31
32 ALLEGRO_DEBUG_CHANNEL("android")
33
34 struct system_data_t {
35 JNIEnv *env;
36 jobject activity_object;
37 jclass input_stream_class;
38 jclass illegal_argument_exception_class;
39 jclass apk_stream_class;
40 jclass image_loader_class;
41 jclass clipboard_class;
42 jclass apk_fs_class;
43
44 ALLEGRO_SYSTEM_ANDROID *system;
45 ALLEGRO_MUTEX *mutex;
46 ALLEGRO_COND *cond;
47 ALLEGRO_THREAD *trampoline;
48 bool trampoline_running;
49
50 ALLEGRO_USTR *user_lib_name;
51 ALLEGRO_USTR *resources_dir;
52 ALLEGRO_USTR *data_dir;
53 ALLEGRO_USTR *apk_path;
54 ALLEGRO_USTR *model;
55 ALLEGRO_USTR *manufacturer;
56
57 void *user_lib;
58 int (*user_main)(int argc, char **argv);
59
60 int orientation;
61
62 bool paused;
63 };
64
65 static struct system_data_t system_data;
66 static JavaVM* javavm;
67 static JNIEnv *main_env;
68
69 static const char *_real_al_android_get_os_version(JNIEnv *env);
70
_al_android_is_paused(void)71 bool _al_android_is_paused(void)
72 {
73 return system_data.paused;
74 }
75
_al_android_get_display_orientation(void)76 int _al_android_get_display_orientation(void)
77 {
78 return system_data.orientation;
79 }
80
_al_android_input_stream_class(void)81 jclass _al_android_input_stream_class(void)
82 {
83 return system_data.input_stream_class;
84 }
85
_al_android_apk_stream_class(void)86 jclass _al_android_apk_stream_class(void)
87 {
88 return system_data.apk_stream_class;
89 }
90
_al_android_image_loader_class(void)91 jclass _al_android_image_loader_class(void)
92 {
93 return system_data.image_loader_class;
94 }
95
_al_android_clipboard_class(void)96 jclass _al_android_clipboard_class(void)
97 {
98 return system_data.clipboard_class;
99 }
100
_al_android_activity_object()101 jobject _al_android_activity_object()
102 {
103 return system_data.activity_object;
104 }
105
_al_android_apk_fs_class(void)106 jclass _al_android_apk_fs_class(void)
107 {
108 return system_data.apk_fs_class;
109 }
110
111 static void finish_activity(JNIEnv *env);
112
113 static bool already_cleaned_up = false;
114
115 /* NOTE: don't put any ALLEGRO_DEBUG in here! */
android_cleanup(bool uninstall_system)116 static void android_cleanup(bool uninstall_system)
117 {
118 if (already_cleaned_up) {
119 return;
120 }
121
122 already_cleaned_up = true;
123
124 if (uninstall_system) {
125 /* I don't think android calls our atexit() stuff since we're in a shared lib
126 so make sure al_uninstall_system is called */
127 al_uninstall_system();
128 }
129
130 finish_activity(_al_android_get_jnienv());
131
132 (*javavm)->DetachCurrentThread(javavm);
133 }
134
android_app_trampoline(ALLEGRO_THREAD * thr,void * arg)135 static void *android_app_trampoline(ALLEGRO_THREAD *thr, void *arg)
136 {
137 const int argc = 1;
138 const char *argv[2] = {system_data.user_lib, NULL};
139 int ret;
140
141 (void)thr;
142 (void)arg;
143
144 ALLEGRO_DEBUG("signaling running");
145
146 al_lock_mutex(system_data.mutex);
147 system_data.trampoline_running = true;
148 al_broadcast_cond(system_data.cond);
149 al_unlock_mutex(system_data.mutex);
150
151 ALLEGRO_DEBUG("entering main function %p", system_data.user_main);
152
153 ret = (system_data.user_main)(argc, (char **)argv);
154
155 /* Can we do anything with this exit code? */
156 ALLEGRO_DEBUG("returned from main function, exit code = %d", ret);
157
158 /* NOTE: don't put any ALLEGRO_DEBUG in here after running main! */
159
160 android_cleanup(true);
161
162 return NULL;
163 }
164
165 /* called by JNI/Java */
JNI_OnLoad(JavaVM * vm,void * reserved)166 jint JNI_OnLoad(JavaVM* vm, void* reserved)
167 {
168 (void)reserved;
169 javavm = vm;
170 return JNI_VERSION_1_4;
171 }
172
173 JNI_FUNC(bool, AllegroActivity, nativeOnCreate, (JNIEnv *env, jobject obj))
174 {
175 ALLEGRO_SYSTEM_ANDROID *na_sys = NULL;
176 jclass iae;
177 jclass aisc;
178 jclass asc;
179
180 ALLEGRO_DEBUG("entered nativeOnCreate");
181
182 // we're already initialized, we REALLY don't want to run all the stuff below again.
183 if(system_data.system) {
184 return true;
185 }
186
187 pthread_t self = pthread_self();
188 ALLEGRO_DEBUG("pthread_self:%p", (void*)self);
189 ALLEGRO_DEBUG("nativeOnCreate begin");
190
191 memset(&system_data, 0, sizeof(system_data));
192
193 ALLEGRO_DEBUG("grab activity global refs");
194 system_data.env = env;
195 system_data.activity_object = (*env)->NewGlobalRef(env, obj);
196
197 iae = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
198 system_data.illegal_argument_exception_class = (*env)->NewGlobalRef(env, iae);
199
200 aisc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroInputStream");
201 system_data.input_stream_class = (*env)->NewGlobalRef(env, aisc);
202
203 asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroAPKStream");
204 system_data.apk_stream_class = (*env)->NewGlobalRef(env, asc);
205
206 asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/ImageLoader");
207 system_data.image_loader_class = (*env)->NewGlobalRef(env, asc);
208
209 asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/Clipboard");
210 system_data.clipboard_class = (*env)->NewGlobalRef(env, asc);
211
212 asc = (*env)->FindClass(env, ALLEGRO_ANDROID_PACKAGE_NAME_SLASH "/AllegroAPKList");
213 system_data.apk_fs_class = (*env)->NewGlobalRef(env, asc);
214
215 ALLEGRO_DEBUG("create mutex and cond objects");
216 system_data.mutex = al_create_mutex();
217 system_data.cond = al_create_cond();
218
219 ALLEGRO_DEBUG("get directories");
220 system_data.user_lib_name = _jni_callStringMethod(env, system_data.activity_object, "getUserLibName", "()Ljava/lang/String;");
221 system_data.resources_dir = _jni_callStringMethod(env, system_data.activity_object, "getResourcesDir", "()Ljava/lang/String;");
222 system_data.data_dir = _jni_callStringMethod(env, system_data.activity_object, "getPubDataDir", "()Ljava/lang/String;");
223 system_data.apk_path = _jni_callStringMethod(env, system_data.activity_object, "getApkPath", "()Ljava/lang/String;");
224 system_data.model = _jni_callStringMethod(env, system_data.activity_object, "getModel", "()Ljava/lang/String;");
225 system_data.manufacturer = _jni_callStringMethod(env, system_data.activity_object, "getManufacturer", "()Ljava/lang/String;");
226 ALLEGRO_DEBUG("resources_dir: %s", al_cstr(system_data.resources_dir));
227 ALLEGRO_DEBUG("data_dir: %s", al_cstr(system_data.data_dir));
228 ALLEGRO_DEBUG("apk_path: %s", al_cstr(system_data.apk_path));
229 ALLEGRO_DEBUG("model: %s", al_cstr(system_data.model));
230 ALLEGRO_DEBUG("manufacturer: %s", al_cstr(system_data.manufacturer));
231
232 ALLEGRO_DEBUG("creating ALLEGRO_SYSTEM_ANDROID struct");
233 na_sys = system_data.system = (ALLEGRO_SYSTEM_ANDROID*)al_malloc(sizeof *na_sys);
234 memset(na_sys, 0, sizeof *na_sys);
235
236 ALLEGRO_DEBUG("get system pointer");
237 ALLEGRO_SYSTEM *sys = &na_sys->system;
238 ALLEGRO_DEBUG("get system interface");
239 sys->vt = _al_system_android_interface();
240
241 ALLEGRO_DEBUG("init display vector");
242 _al_vector_init(&sys->displays, sizeof(ALLEGRO_DISPLAY_ANDROID *));
243
244 ALLEGRO_DEBUG("init time");
245 _al_unix_init_time();
246
247 const char *user_lib_name = al_cstr(system_data.user_lib_name);
248 ALLEGRO_DEBUG("load user lib: %s", user_lib_name);
249 system_data.user_lib = dlopen(user_lib_name, RTLD_LAZY|RTLD_GLOBAL);
250 if (!system_data.user_lib) {
251 ALLEGRO_ERROR("failed to load user lib: %s", user_lib_name);
252 ALLEGRO_ERROR("%s", dlerror());
253 return false;
254 }
255
256 system_data.user_main = dlsym(system_data.user_lib, "main");
257 if (!system_data.user_main) {
258 ALLEGRO_ERROR("failed to locate symbol main: %s", dlerror());
259 dlclose(system_data.user_lib);
260 return false;
261 }
262 ALLEGRO_DEBUG("main function address: %p\n", system_data.user_main);
263
264 ALLEGRO_DEBUG("creating trampoline for app thread");
265 system_data.trampoline = al_create_thread(android_app_trampoline, NULL);
266 al_start_thread(system_data.trampoline);
267
268 ALLEGRO_DEBUG("waiting for app trampoline to signal running");
269 al_lock_mutex(system_data.mutex);
270 while(!system_data.trampoline_running) {
271 al_wait_cond(system_data.cond, system_data.mutex);
272 }
273 al_unlock_mutex(system_data.mutex);
274
275 ALLEGRO_DEBUG("setup done. returning to dalvik.");
276
277 return true;
278 }
279
280
281 JNI_FUNC(void, AllegroActivity, nativeOnPause, (JNIEnv *env, jobject obj))
282 {
283 (void)env;
284 (void)obj;
285
286 ALLEGRO_DEBUG("pause activity\n");
287
288 system_data.paused = true;
289
290 ALLEGRO_SYSTEM *sys = (void *)al_get_system_driver();
291
292 if (!system_data.system || !sys) {
293 ALLEGRO_DEBUG("no system driver");
294 return;
295 }
296
297 if (!_al_vector_size(&sys->displays)) {
298 ALLEGRO_DEBUG("no display, not sending SWITCH_OUT event");
299 return;
300 }
301
302 ALLEGRO_DISPLAY *display = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0);
303
304 if (display) {
305 ALLEGRO_EVENT event;
306 _al_event_source_lock(&display->es);
307
308 if(_al_event_source_needs_to_generate_event(&display->es)) {
309 event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_OUT;
310 event.display.timestamp = al_current_time();
311 _al_event_source_emit_event(&display->es, &event);
312 }
313 _al_event_source_unlock(&display->es);
314 }
315 }
316
317 JNI_FUNC(void, AllegroActivity, nativeOnResume, (JNIEnv *env, jobject obj))
318 {
319 ALLEGRO_SYSTEM *sys = &system_data.system->system;
320 ALLEGRO_DISPLAY *d = NULL;
321
322 (void)obj;
323
324 system_data.paused = false;
325
326 ALLEGRO_DEBUG("resume activity");
327
328 if(!system_data.system || !sys) {
329 ALLEGRO_DEBUG("no system driver");
330 return;
331 }
332
333 if(!_al_vector_size(&sys->displays)) {
334 ALLEGRO_DEBUG("no display, not sending SWITCH_IN event");
335 return;
336 }
337
338 d = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0);
339 ALLEGRO_DEBUG("got display: %p", d);
340
341 if(!((ALLEGRO_DISPLAY_ANDROID*)d)->created) {
342 _al_android_create_surface(env, true); // request android create our surface
343 }
344
345 ALLEGRO_DISPLAY *display = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0);
346
347 if (display) {
348 ALLEGRO_EVENT event;
349 _al_event_source_lock(&display->es);
350
351 if(_al_event_source_needs_to_generate_event(&display->es)) {
352 event.display.type = ALLEGRO_EVENT_DISPLAY_SWITCH_IN;
353 event.display.timestamp = al_current_time();
354 _al_event_source_emit_event(&display->es, &event);
355 }
356 _al_event_source_unlock(&display->es);
357 }
358 }
359
360 /* NOTE: don't put any ALLEGRO_DEBUG in here! */
361 JNI_FUNC(void, AllegroActivity, nativeOnDestroy, (JNIEnv *env, jobject obj))
362 {
363 (void)obj;
364
365 /* onDestroy can be called before main returns, for example if you start
366 * a new activity, your Allegro game will get onDestroy when it returns.
367 * At that point there's nothing you can do and any code you execute will
368 * crash, so this attempts to handle that more gracefully. Calling
369 * android_cleanup() eventually leads back here anyway. We ask android_cleanup
370 * not to call al_uninstall_system because GPU access causes a crash at
371 * this point (cleaning up bitmaps/displays etc.) The trampoline will exit
372 * eventually too so we guard against android_cleanup() being called twice.
373 */
374 bool main_returned = _jni_callBooleanMethodV(
375 env,
376 system_data.activity_object,
377 "getMainReturned",
378 "()Z"
379 );
380
381 if (!main_returned) {
382 exit(0);
383 }
384
385 if(!system_data.user_lib) {
386 return;
387 }
388
389 system_data.user_main = NULL;
390 if(dlclose(system_data.user_lib) != 0) {
391 return;
392 }
393
394 (*env)->DeleteGlobalRef(env, system_data.activity_object);
395 (*env)->DeleteGlobalRef(env, system_data.illegal_argument_exception_class);
396 (*env)->DeleteGlobalRef(env, system_data.input_stream_class);
397
398 free(system_data.system);
399
400 memset(&system_data, 0, sizeof(system_data));
401 }
402
403 JNI_FUNC(void, AllegroActivity, nativeOnOrientationChange, (JNIEnv *env, jobject obj, int orientation, bool init))
404 {
405 ALLEGRO_SYSTEM *sys = &system_data.system->system;
406 ALLEGRO_DISPLAY *d = NULL;
407 ALLEGRO_EVENT event;
408
409 (void)env; (void)obj;
410
411 ALLEGRO_DEBUG("got orientation change!");
412
413 system_data.orientation = orientation;
414
415 if (!init) {
416
417 /* no display, just skip */
418 if (!_al_vector_size(&sys->displays)) {
419 ALLEGRO_DEBUG("no display, not sending orientation change event");
420 return;
421 }
422
423 d = *(ALLEGRO_DISPLAY**)_al_vector_ref(&sys->displays, 0);
424 ASSERT(d != NULL);
425
426 ALLEGRO_DEBUG("locking display event source: %p %p", d, &d->es);
427
428 _al_event_source_lock(&d->es);
429
430 if(_al_event_source_needs_to_generate_event(&d->es)) {
431 ALLEGRO_DEBUG("emit event");
432 event.display.type = ALLEGRO_EVENT_DISPLAY_ORIENTATION;
433 event.display.timestamp = al_current_time();
434 event.display.orientation = orientation;
435 _al_event_source_emit_event(&d->es, &event);
436 }
437
438 ALLEGRO_DEBUG("unlocking display event source");
439 _al_event_source_unlock(&d->es);
440
441 }
442 }
443
444 JNI_FUNC(void, AllegroActivity, nativeSendJoystickConfigurationEvent, (JNIEnv *env, jobject obj))
445 {
446 (void)env;
447 (void)obj;
448
449 if (!al_is_joystick_installed()) {
450 return;
451 }
452
453 ALLEGRO_EVENT_SOURCE *es = al_get_joystick_event_source();
454 _al_event_source_lock(es);
455 ALLEGRO_EVENT event;
456 event.type = ALLEGRO_EVENT_JOYSTICK_CONFIGURATION;
457 _al_event_source_emit_event(es, &event);
458 _al_event_source_unlock(es);
459 }
460
461 /* NOTE: don't put any ALLEGRO_DEBUG in here! */
finish_activity(JNIEnv * env)462 static void finish_activity(JNIEnv *env)
463 {
464 _jni_callVoidMethod(env, system_data.activity_object, "postFinish");
465 }
466
android_initialize(int flags)467 static ALLEGRO_SYSTEM *android_initialize(int flags)
468 {
469 (void)flags;
470
471 ALLEGRO_DEBUG("android_initialize");
472
473 /* This was stored before user main ran, to make it easy and accessible
474 * the same way for all threads, we set it in tls
475 */
476 _al_android_set_jnienv(main_env);
477
478 return &system_data.system->system;
479 }
480
android_get_joystick_driver(void)481 static ALLEGRO_JOYSTICK_DRIVER *android_get_joystick_driver(void)
482 {
483 return &_al_android_joystick_driver;
484 }
485
android_get_num_video_adapters(void)486 static int android_get_num_video_adapters(void)
487 {
488 return 1;
489 }
490
android_get_monitor_info(int adapter,ALLEGRO_MONITOR_INFO * info)491 static bool android_get_monitor_info(int adapter, ALLEGRO_MONITOR_INFO *info)
492 {
493 if (adapter >= android_get_num_video_adapters())
494 return false;
495
496 JNIEnv * env = (JNIEnv *)_al_android_get_jnienv();
497 jobject rect = _jni_callObjectMethod(env, _al_android_activity_object(), "getDisplaySize", "()Landroid/graphics/Rect;");
498
499 info->x1 = 0;
500 info->y1 = 0;
501 info->x2 = _jni_callIntMethod(env, rect, "width");
502 info->y2 = _jni_callIntMethod(env, rect, "height");
503
504 ALLEGRO_DEBUG("Monitor Info: %d:%d", info->x2, info->y2);
505
506 return true;
507 }
508
android_shutdown_system(void)509 static void android_shutdown_system(void)
510 {
511 ALLEGRO_SYSTEM *s = al_get_system_driver();
512 /* Close all open displays. */
513 while (_al_vector_size(&s->displays) > 0) {
514 ALLEGRO_DISPLAY **dptr = _al_vector_ref(&s->displays, 0);
515 ALLEGRO_DISPLAY *d = *dptr;
516 al_destroy_display(d);
517 }
518 _al_vector_free(&s->displays);
519 }
520
android_inhibit_screensaver(bool inhibit)521 static bool android_inhibit_screensaver(bool inhibit)
522 {
523 return _jni_callBooleanMethodV(_al_android_get_jnienv(), system_data.activity_object, "inhibitScreenLock", "(Z)Z", inhibit);
524 }
525
526 static ALLEGRO_SYSTEM_INTERFACE *android_vt;
527
_al_system_android_interface()528 ALLEGRO_SYSTEM_INTERFACE *_al_system_android_interface()
529 {
530 if(android_vt)
531 return android_vt;
532
533 android_vt = al_malloc(sizeof *android_vt);
534 memset(android_vt, 0, sizeof *android_vt);
535
536 android_vt->id = ALLEGRO_SYSTEM_ID_ANDROID;
537 android_vt->initialize = android_initialize;
538 android_vt->get_display_driver = _al_get_android_display_driver;
539 android_vt->get_keyboard_driver = _al_get_android_keyboard_driver;
540 android_vt->get_mouse_driver = _al_get_android_mouse_driver;
541 android_vt->get_touch_input_driver = _al_get_android_touch_input_driver;
542 android_vt->get_joystick_driver = android_get_joystick_driver;
543 android_vt->get_num_video_adapters = android_get_num_video_adapters;
544 android_vt->get_monitor_info = android_get_monitor_info;
545 android_vt->get_path = _al_android_get_path;
546 android_vt->shutdown_system = android_shutdown_system;
547 android_vt->inhibit_screensaver = android_inhibit_screensaver;
548 android_vt->get_time = _al_unix_get_time;
549 android_vt->rest = _al_unix_rest;
550 android_vt->init_timeout = _al_unix_init_timeout;
551
552 return android_vt;
553 }
554
_al_android_get_path(int id)555 ALLEGRO_PATH *_al_android_get_path(int id)
556 {
557 ALLEGRO_PATH *path = NULL;
558
559 switch(id) {
560 case ALLEGRO_RESOURCES_PATH:
561 /* path to bundle's files */
562 path = al_create_path_for_directory(al_cstr(system_data.resources_dir));
563 break;
564
565 case ALLEGRO_TEMP_PATH:
566 case ALLEGRO_USER_DATA_PATH:
567 case ALLEGRO_USER_HOME_PATH:
568 case ALLEGRO_USER_SETTINGS_PATH:
569 case ALLEGRO_USER_DOCUMENTS_PATH:
570 /* path to sdcard */
571 path = al_create_path_for_directory(al_cstr(system_data.data_dir));
572 break;
573
574 case ALLEGRO_EXENAME_PATH:
575 /* bundle path + bundle name */
576 // FIXME!
577 path = al_create_path(al_cstr(system_data.apk_path));
578 break;
579
580 default:
581 path = al_create_path_for_directory("/DANGER/WILL/ROBINSON");
582 break;
583 }
584
585 return path;
586 }
587
_real_al_android_get_os_version(JNIEnv * env)588 static const char *_real_al_android_get_os_version(JNIEnv *env)
589 {
590 static char buffer[25];
591 ALLEGRO_USTR *s = _jni_callStringMethod(env, system_data.activity_object, "getOsVersion", "()Ljava/lang/String;");
592 strncpy(buffer, al_cstr(s), 25);
593 al_ustr_free(s);
594 return buffer;
595 }
596
597 /* Function: al_android_get_os_version
598 */
al_android_get_os_version(void)599 const char *al_android_get_os_version(void)
600 {
601 return _real_al_android_get_os_version(_al_android_get_jnienv());
602 }
603
_al_android_thread_created(void)604 void _al_android_thread_created(void)
605 {
606 JNIEnv *env;
607 JavaVMAttachArgs attach_args = { JNI_VERSION_1_4, "trampoline", NULL };
608 (*javavm)->AttachCurrentThread(javavm, &env, &attach_args);
609 /* This function runs once before al_init, so before TLS is initialized
610 * so we save the environment and set it later in that case.
611 */
612 ALLEGRO_SYSTEM *s = al_get_system_driver();
613 if (s && s->installed) {
614 _al_android_set_jnienv(env);
615 }
616 else {
617 main_env = env;
618 }
619 }
620
_al_android_thread_ended(void)621 void _al_android_thread_ended(void)
622 {
623 (*javavm)->DetachCurrentThread(javavm);
624 }
625
_al_android_set_capture_volume_keys(ALLEGRO_DISPLAY * display,bool onoff)626 void _al_android_set_capture_volume_keys(ALLEGRO_DISPLAY *display, bool onoff)
627 {
628 ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)display;
629 _jni_callVoidMethodV(_al_android_get_jnienv(), d->surface_object, "setCaptureVolumeKeys", "(Z)V", onoff);
630 }
631
632 /* register system interfaces */
633
_al_register_system_interfaces(void)634 void _al_register_system_interfaces(void)
635 {
636 ALLEGRO_SYSTEM_INTERFACE **add;
637
638 /* add the native activity driver */
639 add = _al_vector_alloc_back(&_al_system_interfaces);
640 *add = _al_system_android_interface();
641
642 /* TODO: add the non native activity driver */
643 }
644
645 /* Function: al_android_get_jni_env
646 */
al_android_get_jni_env(void)647 JNIEnv *al_android_get_jni_env(void)
648 {
649 return _al_android_get_jnienv();
650 }
651
652 /* Function: al_android_get_activity
653 */
al_android_get_activity(void)654 jobject al_android_get_activity(void)
655 {
656 return _al_android_activity_object();
657 }
658
659 /* vim: set sts=3 sw=3 et: */
660