| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277 |
- // Copyright 2014 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // +build android
- #include <android/log.h>
- #include <dlfcn.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <stdint.h>
- #include <stdbool.h>
- #include <string.h>
- #include "_cgo_export.h"
- #define LOG_INFO(...) __android_log_print(ANDROID_LOG_INFO, "Fyne", __VA_ARGS__)
- #define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "Fyne", __VA_ARGS__)
- static jclass current_class;
- static jclass find_class(JNIEnv *env, const char *class_name) {
- jclass clazz = (*env)->FindClass(env, class_name);
- if (clazz == NULL) {
- (*env)->ExceptionClear(env);
- LOG_FATAL("cannot find %s", class_name);
- return NULL;
- }
- return clazz;
- }
- static jmethodID find_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
- jmethodID m = (*env)->GetMethodID(env, clazz, name, sig);
- if (m == 0) {
- (*env)->ExceptionClear(env);
- LOG_FATAL("cannot find method %s %s", name, sig);
- return 0;
- }
- return m;
- }
- static jmethodID find_static_method(JNIEnv *env, jclass clazz, const char *name, const char *sig) {
- jmethodID m = (*env)->GetStaticMethodID(env, clazz, name, sig);
- if (m == 0) {
- (*env)->ExceptionClear(env);
- LOG_FATAL("cannot find method %s %s", name, sig);
- return 0;
- }
- return m;
- }
- static jmethodID key_rune_method;
- static jmethodID show_keyboard_method;
- static jmethodID hide_keyboard_method;
- static jmethodID show_file_open_method;
- static jmethodID show_file_save_method;
- jint JNI_OnLoad(JavaVM* vm, void* reserved) {
- JNIEnv* env;
- if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
- return -1;
- }
- return JNI_VERSION_1_6;
- }
- static int main_running = 0;
- // Entry point from our subclassed NativeActivity.
- //
- // By here, the Go runtime has been initialized (as we are running in
- // -buildmode=c-shared) but the first time it is called, Go's main.main
- // hasn't been called yet.
- //
- // The Activity may be created and destroyed multiple times throughout
- // the life of a single process. Each time, onCreate is called.
- void ANativeActivity_onCreate(ANativeActivity *activity, void* savedState, size_t savedStateSize) {
- if (!main_running) {
- JNIEnv* env = activity->env;
- // Note that activity->clazz is mis-named.
- current_class = (*env)->GetObjectClass(env, activity->clazz);
- current_class = (*env)->NewGlobalRef(env, current_class);
- key_rune_method = find_static_method(env, current_class, "getRune", "(III)I");
- show_keyboard_method = find_static_method(env, current_class, "showKeyboard", "(I)V");
- hide_keyboard_method = find_static_method(env, current_class, "hideKeyboard", "()V");
- show_file_open_method = find_static_method(env, current_class, "showFileOpen", "(Ljava/lang/String;)V");
- show_file_save_method = find_static_method(env, current_class, "showFileSave", "(Ljava/lang/String;Ljava/lang/String;)V");
- setCurrentContext(activity->vm, (*env)->NewGlobalRef(env, activity->clazz));
- // Set FILESDIR
- if (setenv("FILESDIR", activity->internalDataPath, 1) != 0) {
- LOG_INFO("setenv(\"FILESDIR\", \"%s\", 1) failed: %d", activity->internalDataPath, errno);
- }
- // Set TMPDIR.
- jmethodID gettmpdir = find_method(env, current_class, "getTmpdir", "()Ljava/lang/String;");
- jstring jpath = (jstring)(*env)->CallObjectMethod(env, activity->clazz, gettmpdir, NULL);
- const char* tmpdir = (*env)->GetStringUTFChars(env, jpath, NULL);
- if (setenv("TMPDIR", tmpdir, 1) != 0) {
- LOG_INFO("setenv(\"TMPDIR\", \"%s\", 1) failed: %d", tmpdir, errno);
- }
- (*env)->ReleaseStringUTFChars(env, jpath, tmpdir);
- // Call the Go main.main.
- uintptr_t mainPC = (uintptr_t)dlsym(RTLD_DEFAULT, "main.main");
- if (!mainPC) {
- LOG_FATAL("missing main.main");
- }
- callMain(mainPC);
- main_running = 1;
- }
- // These functions match the methods on Activity, described at
- // http://developer.android.com/reference/android/app/Activity.html
- //
- // Note that onNativeWindowResized is not called on resize. Avoid it.
- // https://code.google.com/p/android/issues/detail?id=180645
- activity->callbacks->onStart = onStart;
- activity->callbacks->onResume = onResume;
- activity->callbacks->onSaveInstanceState = onSaveInstanceState;
- activity->callbacks->onPause = onPause;
- activity->callbacks->onStop = onStop;
- activity->callbacks->onDestroy = onDestroy;
- activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
- activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
- activity->callbacks->onNativeWindowRedrawNeeded = onNativeWindowRedrawNeeded;
- activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
- activity->callbacks->onInputQueueCreated = onInputQueueCreated;
- activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
- activity->callbacks->onConfigurationChanged = onConfigurationChanged;
- activity->callbacks->onLowMemory = onLowMemory;
- onCreate(activity);
- }
- // TODO(crawshaw): Test configuration on more devices.
- static const EGLint RGB_888[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_BLUE_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_RED_SIZE, 8,
- EGL_DEPTH_SIZE, 16,
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_NONE
- };
- EGLDisplay display = NULL;
- EGLSurface surface = NULL;
- EGLContext context = NULL;
- static char* initEGLDisplay() {
- display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- if (!eglInitialize(display, 0, 0)) {
- return "EGL initialize failed";
- }
- return NULL;
- }
- char* createEGLSurface(ANativeWindow* window) {
- char* err;
- EGLint numConfigs, format;
- EGLConfig config;
- if (display == 0) {
- if ((err = initEGLDisplay()) != NULL) {
- return err;
- }
- }
- if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
- return "EGL choose RGB_888 config failed";
- }
- if (numConfigs <= 0) {
- return "EGL no config found";
- }
- eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
- if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
- return "EGL set buffers geometry failed";
- }
- surface = eglCreateWindowSurface(display, config, window, NULL);
- if (surface == EGL_NO_SURFACE) {
- return "EGL create surface failed";
- }
- if (context == NULL) {
- const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
- context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
- }
- if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
- return "eglMakeCurrent failed";
- }
- return NULL;
- }
- char* destroyEGLSurface() {
- if (!eglDestroySurface(display, surface)) {
- return "EGL destroy surface failed";
- }
- return NULL;
- }
- int32_t getKeyRune(JNIEnv* env, AInputEvent* e) {
- return (int32_t)(*env)->CallStaticIntMethod(
- env,
- current_class,
- key_rune_method,
- AInputEvent_getDeviceId(e),
- AKeyEvent_getKeyCode(e),
- AKeyEvent_getMetaState(e)
- );
- }
- void showKeyboard(JNIEnv* env, int keyboardType) {
- (*env)->CallStaticVoidMethod(
- env,
- current_class,
- show_keyboard_method,
- keyboardType
- );
- }
- void hideKeyboard(JNIEnv* env) {
- (*env)->CallStaticVoidMethod(
- env,
- current_class,
- hide_keyboard_method
- );
- }
- void showFileOpen(JNIEnv* env, char* mimes) {
- jstring mimesJString = (*env)->NewStringUTF(env, mimes);
- (*env)->CallStaticVoidMethod(
- env,
- current_class,
- show_file_open_method,
- mimesJString
- );
- }
- void showFileSave(JNIEnv* env, char* mimes, char* filename) {
- jstring mimesJString = (*env)->NewStringUTF(env, mimes);
- jstring filenameJString = (*env)->NewStringUTF(env, filename);
- (*env)->CallStaticVoidMethod(
- env,
- current_class,
- show_file_save_method,
- mimesJString,
- filenameJString
- );
- }
- void Java_org_golang_app_GoNativeActivity_filePickerReturned(JNIEnv *env, jclass clazz, jstring str) {
- const char* cstr = (*env)->GetStringUTFChars(env, str, JNI_FALSE);
- filePickerReturned((char*)cstr);
- }
- void Java_org_golang_app_GoNativeActivity_insetsChanged(JNIEnv *env, jclass clazz, int top, int bottom, int left, int right) {
- insetsChanged(top, bottom, left, right);
- }
- void Java_org_golang_app_GoNativeActivity_keyboardTyped(JNIEnv *env, jclass clazz, jstring str) {
- const char* cstr = (*env)->GetStringUTFChars(env, str, JNI_FALSE);
- keyboardTyped((char*)cstr);
- }
- void Java_org_golang_app_GoNativeActivity_keyboardDelete(JNIEnv *env, jclass clazz) {
- keyboardDelete();
- }
- void Java_org_golang_app_GoNativeActivity_setDarkMode(JNIEnv *env, jclass clazz, jboolean dark) {
- setDarkMode((bool)dark);
- }
|