diff --git a/makepanda/makepanda.py b/makepanda/makepanda.py index 7101b473d7..f3bdb167af 100755 --- a/makepanda/makepanda.py +++ b/makepanda/makepanda.py @@ -4948,6 +4948,7 @@ if GetTarget() == 'android': TargetAdd('org/panda3d/android/PandaActivity$1.class', opts=OPTS+['DEPENDENCYONLY'], input='PandaActivity.java') TargetAdd('org/panda3d/android/PandaActivity$2.class', opts=OPTS+['DEPENDENCYONLY'], input='PandaActivity.java') TargetAdd('org/panda3d/android/PythonActivity.class', opts=OPTS, input='PythonActivity.java') + TargetAdd('org/panda3d/android/PythonActivity$ActivityResultListener.class', opts=OPTS+['DEPENDENCYONLY'], input='PythonActivity.java') TargetAdd('classes.dex', input='org/panda3d/android/NativeIStream.class') TargetAdd('classes.dex', input='org/panda3d/android/NativeOStream.class') @@ -4955,6 +4956,7 @@ if GetTarget() == 'android': TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity$1.class') TargetAdd('classes.dex', input='org/panda3d/android/PandaActivity$2.class') TargetAdd('classes.dex', input='org/panda3d/android/PythonActivity.class') + TargetAdd('classes.dex', input='org/panda3d/android/PythonActivity$ActivityResultListener.class') TargetAdd('p3android_composite1.obj', opts=OPTS, input='p3android_composite1.cxx') TargetAdd('libp3android.dll', input='p3android_composite1.obj') diff --git a/panda/src/android/PandaActivity.java b/panda/src/android/PandaActivity.java index 4c7e64b4f8..6c59886be4 100644 --- a/panda/src/android/PandaActivity.java +++ b/panda/src/android/PandaActivity.java @@ -81,6 +81,16 @@ public class PandaActivity extends NativeActivity { return Thread.currentThread().getName(); } + /** + * Called by android_native_app_glue to spawn the application thread. + * Gets passed a function pointer and a data pointer to pass to it. + */ + protected void spawnAppThread(long ptr, long data) { + new Thread(() -> { + nativeThreadEntry(ptr, data); + }).start(); + } + /** * Maps the blob to memory and returns the pointer. */ @@ -193,4 +203,5 @@ public class PandaActivity extends NativeActivity { } private static native long nativeMmap(int fd, long off, long len); + private static native void nativeThreadEntry(long ptr, long data); } diff --git a/panda/src/android/PythonActivity.java b/panda/src/android/PythonActivity.java index 731ed4d54c..68b4720be8 100644 --- a/panda/src/android/PythonActivity.java +++ b/panda/src/android/PythonActivity.java @@ -15,6 +15,12 @@ package org.panda3d.android; import org.panda3d.android.PandaActivity; +import android.content.Intent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + /** * Extends PandaActivity with some things that are useful in a Python * application. @@ -26,4 +32,39 @@ public class PythonActivity extends PandaActivity { public PythonActivity() { mActivity = this; } + + // Helper code to further support plyer. + public interface ActivityResultListener { + void onActivityResult(int requestCode, int resultCode, Intent data); + } + + private List activityResultListeners = null; + + public void registerActivityResultListener(ActivityResultListener listener) { + if (this.activityResultListeners == null) { + this.activityResultListeners = Collections.synchronizedList(new ArrayList()); + } + this.activityResultListeners.add(listener); + } + + public void unregisterActivityResultListener(ActivityResultListener listener) { + if (this.activityResultListeners == null) { + return; + } + this.activityResultListeners.remove(listener); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent intent) { + if (this.activityResultListeners == null) { + return; + } + this.onResume(); + synchronized (this.activityResultListeners) { + Iterator iterator = this.activityResultListeners.iterator(); + while (iterator.hasNext()) { + iterator.next().onActivityResult(requestCode, resultCode, intent); + } + } + } } diff --git a/panda/src/android/android_native_app_glue.c b/panda/src/android/android_native_app_glue.c index 1e63c5ef59..38aff2df51 100644 --- a/panda/src/android/android_native_app_glue.c +++ b/panda/src/android/android_native_app_glue.c @@ -255,10 +255,19 @@ static struct android_app* android_app_create(ANativeActivity* activity, android_app->msgread = msgpipe[0]; android_app->msgwrite = msgpipe[1]; + // Spawn the app thread in Java so it gets a valid class loader. + JNIEnv *env = activity->env; + jclass activity_class = (*env)->GetObjectClass(env, activity->clazz); + jmethodID method = (*env)->GetMethodID(env, activity_class, "spawnAppThread", "(JJ)V"); + LOGE("got function pointer: %ld, data: %ld, env: %ld", (jlong)(void *)android_app_entry, (jlong)(void *)android_app, (jlong)(void *)env); + (*env)->CallVoidMethod(env, activity->clazz, method, (void *)android_app_entry, (void *)android_app); + + /* pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); pthread_create(&android_app->thread, &attr, android_app_entry, android_app); + */ // Wait for thread to start. pthread_mutex_lock(&android_app->mutex); diff --git a/panda/src/android/android_native_app_glue.h b/panda/src/android/android_native_app_glue.h index 89eafe3ff9..7e4149e229 100644 --- a/panda/src/android/android_native_app_glue.h +++ b/panda/src/android/android_native_app_glue.h @@ -168,7 +168,7 @@ struct android_app { int msgread; int msgwrite; - pthread_t thread; + //pthread_t thread; struct android_poll_source cmdPollSource; struct android_poll_source inputPollSource; diff --git a/panda/src/android/config_android.cxx b/panda/src/android/config_android.cxx index 53c22c7b73..75b2d42a8a 100644 --- a/panda/src/android/config_android.cxx +++ b/panda/src/android/config_android.cxx @@ -193,3 +193,10 @@ void android_show_toast(ANativeActivity *activity, const std::string &message, i env->CallVoidMethod(activity->clazz, jni_PandaActivity_showToast, jmsg, (jint)duration); env->DeleteLocalRef(jmsg); } + +/** + * Returns the JNIEnv pointer corresponding to the current thread. + */ +void *SDL_AndroidGetJNIEnv() { + return Thread::get_current_thread()->get_jni_env(); +} diff --git a/panda/src/android/config_android.h b/panda/src/android/config_android.h index 94a417c104..9ff8b2107f 100644 --- a/panda/src/android/config_android.h +++ b/panda/src/android/config_android.h @@ -44,4 +44,9 @@ EXPORT_CLASS Filename android_find_library(ANativeActivity *activity, const std: EXPORT_CLASS void android_set_title(ANativeActivity *activity, const std::string &title); EXPORT_CLASS void android_show_toast(ANativeActivity *activity, const std::string &message, int duration); +// Used to support pyjnius +extern "C" { + EXPORT_CLASS void *SDL_AndroidGetJNIEnv(void); +}; + #endif diff --git a/panda/src/android/jni_PandaActivity.cxx b/panda/src/android/jni_PandaActivity.cxx index af1ae1e140..4d51e98091 100644 --- a/panda/src/android/jni_PandaActivity.cxx +++ b/panda/src/android/jni_PandaActivity.cxx @@ -38,3 +38,11 @@ Java_org_panda3d_android_PandaActivity_nativeMmap(JNIEnv* env, jclass, jint fd, return (jlong)0; } } + +/** + * Calls the given function pointer, passing the given data pointer. + */ +EXPORT_JNI void +Java_org_panda3d_android_PandaActivity_nativeThreadEntry(JNIEnv* env, jobject self, jlong func, jlong data) { + ((void (*)(void *))(void *)func)((void *)data); +}