The open source OpenXR runtime
at prediction-2 206 lines 8.6 kB view raw
1// Copyright 2021-2024, Collabora, Ltd. 2// SPDX-License-Identifier: BSL-1.0 3/*! 4 * @file 5 * @brief Implementation of a callback collection for Android lifecycle events. 6 * @author Rylie Pavlik <rylie.pavlik@collabora.com> 7 * @ingroup aux_android 8 */ 9 10#include "android_lifecycle_callbacks.h" 11 12#include "android_load_class.hpp" 13#include "org.freedesktop.monado.auxiliary.hpp" 14 15#include "xrt/xrt_config_android.h" 16#include "xrt/xrt_android.h" 17#include "util/u_logging.h" 18#include "util/u_generic_callbacks.hpp" 19 20#include "wrap/android.app.h" 21 22#include <memory> 23 24using wrap::android::app::Activity; 25using wrap::org::freedesktop::monado::auxiliary::ActivityLifecycleListener; 26using xrt::auxiliary::android::loadClassFromRuntimeApk; 27using xrt::auxiliary::util::GenericCallbacks; 28 29struct android_lifecycle_callbacks 30{ 31 explicit android_lifecycle_callbacks(xrt_instance_android *xinst_android) : instance_android(xinst_android) {} 32 xrt_instance_android *instance_android; 33 GenericCallbacks<xrt_android_lifecycle_event_handler_t, enum xrt_android_lifecycle_event> callback_collection; 34 ActivityLifecycleListener listener{}; 35}; 36 37int 38android_lifecycle_callbacks_invoke(struct android_lifecycle_callbacks *alc, enum xrt_android_lifecycle_event event); 39 40/*! 41 * JNI functions 42 */ 43 44static void 45on_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 53static void 54on_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 62static void 63on_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 71static void 72on_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 80static void 81on_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 89static void 90on_activity_save_instance_state(JNIEnv *env, jobject thiz, jlong native_callback_ptr, jobject activity) 91{} 92 93static void 94on_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 102static 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}, 110}; 111 112#define CATCH_CLAUSES(ACTION, RET) \ 113 catch (std::exception const &e) \ 114 { \ 115 U_LOG_E("Exception while " ACTION "! %s", e.what()); \ 116 return RET; \ 117 } \ 118 catch (...) \ 119 { \ 120 U_LOG_E("Unknown exception while " ACTION "!"); \ 121 return RET; \ 122 } 123 124int 125android_lifecycle_callbacks_register_callback(struct android_lifecycle_callbacks *alc, 126 xrt_android_lifecycle_event_handler_t callback, 127 enum xrt_android_lifecycle_event event_mask, 128 void *userdata) 129{ 130 try { 131 alc->callback_collection.addCallback(callback, event_mask, userdata); 132 return 0; 133 } 134 CATCH_CLAUSES("adding callback to collection", -1) 135} 136 137int 138android_lifecycle_callbacks_remove_callback(struct android_lifecycle_callbacks *alc, 139 xrt_android_lifecycle_event_handler_t callback, 140 enum xrt_android_lifecycle_event event_mask, 141 void *userdata) 142{ 143 try { 144 return alc->callback_collection.removeCallback(callback, event_mask, userdata); 145 } 146 CATCH_CLAUSES("removing callback", -1) 147} 148 149int 150android_lifecycle_callbacks_invoke(struct android_lifecycle_callbacks *alc, enum xrt_android_lifecycle_event event) 151{ 152 try { 153 return alc->callback_collection.invokeCallbacks( 154 event, [=](enum xrt_android_lifecycle_event event, xrt_android_lifecycle_event_handler_t callback, 155 void *userdata) { return callback(alc->instance_android, event, userdata); }); 156 } 157 CATCH_CLAUSES("invoking callbacks", -1) 158} 159 160struct android_lifecycle_callbacks * 161android_lifecycle_callbacks_create(struct xrt_instance_android *xinst_android) 162{ 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 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])); 184 185 ret->listener = ActivityLifecycleListener::construct(ret.get()); 186 ret->listener.registerCallback(Activity(context)); 187 return ret.release(); 188 } 189 CATCH_CLAUSES("creating callbacks structure", nullptr) 190} 191 192void 193android_lifecycle_callbacks_destroy(struct android_lifecycle_callbacks **ptr_callbacks) 194{ 195 if (ptr_callbacks == nullptr) { 196 return; 197 } 198 struct android_lifecycle_callbacks *alc = *ptr_callbacks; 199 if (alc == nullptr) { 200 return; 201 } 202 203 alc->listener.unregisterCallback(Activity((jobject)xrt_instance_android_get_context(alc->instance_android))); 204 delete alc; 205 *ptr_callbacks = nullptr; 206}