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