The open source OpenXR runtime

a/android: Hook android_lifecycle_callbacks with Java class

Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/1655>

authored by

Jarvis Huang and committed by
Rylie Pavlik
3a7e98a5 84efd4d6

+107 -14
+107
src/xrt/auxiliary/android/android_lifecycle_callbacks.cpp
··· 9 9 10 10 #include "android_lifecycle_callbacks.h" 11 11 12 + #include "android_load_class.hpp" 13 + #include "org.freedesktop.monado.auxiliary.hpp" 14 + 12 15 #include "xrt/xrt_config_android.h" 13 16 #include "xrt/xrt_android.h" 14 17 #include "util/u_logging.h" 15 18 #include "util/u_generic_callbacks.hpp" 16 19 20 + #include "wrap/android.app.h" 21 + 17 22 #include <memory> 18 23 24 + using wrap::android::app::Activity; 25 + using wrap::org::freedesktop::monado::auxiliary::ActivityLifecycleListener; 26 + using xrt::auxiliary::android::loadClassFromRuntimeApk; 19 27 using xrt::auxiliary::util::GenericCallbacks; 20 28 21 29 struct android_lifecycle_callbacks ··· 23 31 explicit android_lifecycle_callbacks(xrt_instance_android *xinst_android) : instance_android(xinst_android) {} 24 32 xrt_instance_android *instance_android; 25 33 GenericCallbacks<xrt_android_lifecycle_event_handler_t, enum xrt_android_lifecycle_event> callback_collection; 34 + ActivityLifecycleListener listener{}; 35 + }; 36 + 37 + int 38 + android_lifecycle_callbacks_invoke(struct android_lifecycle_callbacks *alc, enum xrt_android_lifecycle_event event); 39 + 40 + /*! 41 + * JNI functions 42 + */ 43 + 44 + static void 45 + on_activity_created(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 46 + { 47 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 48 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 49 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_CREATE); 50 + } 51 + } 52 + 53 + static void 54 + on_activity_started(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 55 + { 56 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 57 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 58 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_START); 59 + } 60 + } 61 + 62 + static void 63 + on_activity_resumed(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 64 + { 65 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 66 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 67 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_RESUME); 68 + } 69 + } 70 + 71 + static void 72 + on_activity_paused(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 73 + { 74 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 75 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 76 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_PAUSE); 77 + } 78 + } 79 + 80 + static void 81 + on_activity_stopped(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 82 + { 83 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 84 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 85 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_STOP); 86 + } 87 + } 88 + 89 + static void 90 + on_activity_save_instance_state(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 91 + {} 92 + 93 + static void 94 + on_activity_destroyed(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 95 + { 96 + auto *alc = reinterpret_cast<android_lifecycle_callbacks *>(native_callback_ptr); 97 + if (env->IsSameObject(activity, (jobject)xrt_instance_android_get_context(alc->instance_android))) { 98 + android_lifecycle_callbacks_invoke(alc, XRT_ANDROID_LIVECYCLE_EVENT_ON_DESTROY); 99 + } 100 + } 101 + 102 + static JNINativeMethod methods[] = { 103 + {"nativeOnActivityCreated", "(JLandroid/app/Activity;)V", (void *)&on_activity_created}, 104 + {"nativeOnActivityStarted", "(JLandroid/app/Activity;)V", (void *)&on_activity_started}, 105 + {"nativeOnActivityResumed", "(JLandroid/app/Activity;)V", (void *)&on_activity_resumed}, 106 + {"nativeOnActivityPaused", "(JLandroid/app/Activity;)V", (void *)&on_activity_paused}, 107 + {"nativeOnActivityStopped", "(JLandroid/app/Activity;)V", (void *)&on_activity_stopped}, 108 + {"nativeOnActivitySaveInstanceState", "(JLandroid/app/Activity;)V", (void *)&on_activity_save_instance_state}, 109 + {"nativeOnActivityDestroyed", "(JLandroid/app/Activity;)V", (void *)&on_activity_destroyed}, 26 110 }; 27 111 28 112 #define CATCH_CLAUSES(ACTION, RET) \ ··· 77 161 android_lifecycle_callbacks_create(struct xrt_instance_android *xinst_android) 78 162 { 79 163 try { 164 + jni::init(xrt_instance_android_get_vm(xinst_android)); 165 + jobject context = (jobject)xrt_instance_android_get_context(xinst_android); 166 + if (!jni::env()->IsInstanceOf(context, jni::Class(Activity::getTypeName()).getHandle())) { 167 + // skip if context is not android.app.Activity 168 + U_LOG_W("Context is not Activity, skip"); 169 + return nullptr; 170 + } 171 + 172 + auto clazz = loadClassFromRuntimeApk(context, ActivityLifecycleListener::getFullyQualifiedTypeName()); 173 + if (clazz.isNull()) { 174 + U_LOG_E("Could not load class '%s' from package '%s'", 175 + ActivityLifecycleListener::getFullyQualifiedTypeName(), XRT_ANDROID_PACKAGE); 176 + return nullptr; 177 + } 178 + 80 179 auto ret = std::make_unique<android_lifecycle_callbacks>(xinst_android); 180 + // Teach the wrapper our class before we start to use it. 181 + ActivityLifecycleListener::staticInitClass((jclass)clazz.object().getHandle()); 182 + jni::env()->RegisterNatives((jclass)clazz.object().getHandle(), methods, 183 + sizeof(methods) / sizeof(methods[0])); 81 184 185 + ret->listener = ActivityLifecycleListener::construct(ret.get()); 186 + ret->listener.registerCallback(Activity(context)); 82 187 return ret.release(); 83 188 } 84 189 CATCH_CLAUSES("creating callbacks structure", nullptr) ··· 94 199 if (alc == nullptr) { 95 200 return; 96 201 } 202 + 203 + alc->listener.unregisterCallback(Activity((jobject)xrt_instance_android_get_context(alc->instance_android))); 97 204 delete alc; 98 205 *ptr_callbacks = nullptr; 99 206 }
-14
src/xrt/auxiliary/android/android_lifecycle_callbacks.h
··· 76 76 enum xrt_android_lifecycle_event event_mask, 77 77 void *userdata); 78 78 79 - 80 - /*! 81 - * Invoke all lifecycle event callbacks that match a given event. 82 - * 83 - * @param alc Pointer to self 84 - * @param event The event from @ref xrt_android_lifecycle_event 85 - * 86 - * @return the number of invoked callbacks on success, <0 on error. 87 - * @public @memberof android_lifecycle_callbacks 88 - */ 89 - int 90 - android_lifecycle_callbacks_invoke(struct android_lifecycle_callbacks *alc, enum xrt_android_lifecycle_event event); 91 - 92 - 93 79 #ifdef __cplusplus 94 80 } // extern "C" 95 81 #endif