// Copyright 2020, Collabora, Ltd. // SPDX-License-Identifier: BSL-1.0 // Author: Ryan Pavlik // Author: Lubosz Sarnecki #include "android_custom_surface.h" #include "android_load_class.h" #include "xrt/xrt_config_android.h" #include "util/u_logging.h" #include "wrap/android.app.h" #include "wrap/android.view.h" #include #include "jni.h" using wrap::android::app::Activity; using wrap::android::view::SurfaceHolder; struct android_custom_surface { Activity activity; jni::Class monadoViewClass; jni::Object monadoView; jni::method_t waitGetSurfaceHolderMethod; }; struct android_custom_surface * android_custom_surface_async_start(struct _JavaVM *vm, void *activity) { jni::init(vm); jni::method_t attachToActivity; try { std::unique_ptr ret = std::make_unique(); ret->activity = Activity((jobject)activity); auto info = getAppInfo(XRT_ANDROID_PACKAGE, (jobject)activity); if (info.isNull()) { U_LOG_E( "Could not get application info for package '%s'", "org.freedesktop.monado.openxr_runtime"); return nullptr; } auto clazz = loadClassFromPackage( info, (jobject)activity, "org.freedesktop.monado.auxiliary.MonadoView"); if (clazz.isNull()) { U_LOG_E("Could not load class '%s' from package '%s'", "org.freedesktop.monado.auxiliary.MonadoView", XRT_ANDROID_PACKAGE); return nullptr; } // the 0 is to avoid this being considered "temporary" and to // create a global ref. ret->monadoViewClass = jni::Class((jclass)clazz.object().getHandle(), 0); if (ret->monadoViewClass.isNull()) { U_LOG_E("monadoViewClass was null"); return nullptr; } std::string clazz_name = ret->monadoViewClass.getName(); if (clazz_name != "org.freedesktop.monado.auxiliary.MonadoView") { U_LOG_E("Unexpected class name: %s", clazz_name.c_str()); return nullptr; } if (ret->monadoViewClass.isNull()) { U_LOG_E("MonadoView was null."); return nullptr; } ret->waitGetSurfaceHolderMethod = ret->monadoViewClass.getMethod( "waitGetSurfaceHolder", "(I)Landroid/view/SurfaceHolder;"); attachToActivity = ret->monadoViewClass.getStaticMethod( "attachToActivity", "(Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/" "MonadoView;"); ret->monadoView = ret->monadoViewClass.call( attachToActivity, ret->activity.object()); return ret.release(); } catch (std::exception const &e) { U_LOG_E( "Could not start attaching our custom surface to activity: " "%s", e.what()); return nullptr; } } void android_custom_surface_destroy( struct android_custom_surface **ptr_custom_surface) { if (ptr_custom_surface == NULL) { return; } struct android_custom_surface *custom_surface = *ptr_custom_surface; if (custom_surface == NULL) { return; } delete custom_surface; *ptr_custom_surface = NULL; } ANativeWindow * android_custom_surface_wait_get_surface( struct android_custom_surface *custom_surface, uint64_t timeout_ms) { jni::Object holder = nullptr; try { holder = custom_surface->monadoView.call( custom_surface->waitGetSurfaceHolderMethod, (int)timeout_ms); } catch (std::exception const &e) { // do nothing right now. U_LOG_E( "Could not wait for our custom surface: " "%s", e.what()); return nullptr; } SurfaceHolder surfaceHolder(holder); if (surfaceHolder.isNull()) { return nullptr; } auto surf = surfaceHolder.getSurface(); if (surf.isNull()) { return nullptr; } return ANativeWindow_fromSurface(jni::env(), surf.object().getHandle()); }