2020-09-08 20:09:07 +00:00
|
|
|
// Copyright 2020, Collabora, Ltd.
|
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
2020-10-28 16:29:15 +00:00
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Implementation of native code for Android custom surface.
|
|
|
|
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
|
|
|
* @author Lubosz Sarnecki <lubosz.sarnecki@collabora.com>
|
|
|
|
* @ingroup aux_android
|
|
|
|
*/
|
2020-09-08 20:09:07 +00:00
|
|
|
|
|
|
|
#include "android_custom_surface.h"
|
2022-10-04 02:58:50 +00:00
|
|
|
#include "android_globals.h"
|
2020-10-28 16:30:44 +00:00
|
|
|
#include "android_load_class.hpp"
|
2020-09-08 20:09:07 +00:00
|
|
|
|
|
|
|
#include "xrt/xrt_config_android.h"
|
|
|
|
#include "util/u_logging.h"
|
|
|
|
|
2022-08-31 08:59:30 +00:00
|
|
|
#include "wrap/android.content.h"
|
2022-10-04 02:58:50 +00:00
|
|
|
#include "wrap/android.hardware.display.h"
|
2020-09-08 20:09:07 +00:00
|
|
|
#include "wrap/android.view.h"
|
2020-10-28 16:50:10 +00:00
|
|
|
#include "org.freedesktop.monado.auxiliary.hpp"
|
2020-09-08 20:09:07 +00:00
|
|
|
|
|
|
|
#include <android/native_window_jni.h>
|
|
|
|
|
2022-08-31 08:59:30 +00:00
|
|
|
using wrap::android::content::Context;
|
2022-10-04 02:58:50 +00:00
|
|
|
using wrap::android::hardware::display::DisplayManager;
|
|
|
|
using wrap::android::view::Display;
|
2020-09-08 20:09:07 +00:00
|
|
|
using wrap::android::view::SurfaceHolder;
|
2022-10-04 02:58:50 +00:00
|
|
|
using wrap::android::view::WindowManager_LayoutParams;
|
2020-10-28 16:50:10 +00:00
|
|
|
using wrap::org::freedesktop::monado::auxiliary::MonadoView;
|
2022-08-30 15:41:41 +00:00
|
|
|
using xrt::auxiliary::android::loadClassFromRuntimeApk;
|
2020-09-08 20:09:07 +00:00
|
|
|
|
|
|
|
struct android_custom_surface
|
|
|
|
{
|
2022-10-04 02:58:50 +00:00
|
|
|
explicit android_custom_surface();
|
2020-10-28 15:24:28 +00:00
|
|
|
~android_custom_surface();
|
2022-10-04 02:58:50 +00:00
|
|
|
|
2020-10-28 16:50:10 +00:00
|
|
|
MonadoView monadoView{};
|
2020-10-28 15:24:28 +00:00
|
|
|
jni::Class monadoViewClass{};
|
2020-09-08 20:09:07 +00:00
|
|
|
};
|
|
|
|
|
2020-10-28 16:33:30 +00:00
|
|
|
|
2022-10-04 02:58:50 +00:00
|
|
|
android_custom_surface::android_custom_surface() {}
|
2020-10-28 16:33:30 +00:00
|
|
|
|
2020-10-28 15:24:28 +00:00
|
|
|
android_custom_surface::~android_custom_surface()
|
|
|
|
{
|
2020-10-28 16:33:30 +00:00
|
|
|
// Tell Java that native code is done with this.
|
2020-10-28 16:50:10 +00:00
|
|
|
try {
|
2022-10-04 02:58:50 +00:00
|
|
|
MonadoView::removeFromWindow(monadoView);
|
2020-10-28 16:50:10 +00:00
|
|
|
if (!monadoView.isNull()) {
|
|
|
|
monadoView.markAsDiscardedByNative();
|
2020-10-28 15:24:28 +00:00
|
|
|
}
|
2020-10-28 16:50:10 +00:00
|
|
|
} catch (std::exception const &e) {
|
|
|
|
// Must catch and ignore any exceptions in the destructor!
|
2021-01-14 14:13:48 +00:00
|
|
|
U_LOG_E("Failure while marking MonadoView as discarded: %s", e.what());
|
2020-10-28 15:24:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-08 20:09:07 +00:00
|
|
|
struct android_custom_surface *
|
2022-10-04 02:58:50 +00:00
|
|
|
android_custom_surface_async_start(struct _JavaVM *vm, void *context, int32_t display_id)
|
2020-09-08 20:09:07 +00:00
|
|
|
{
|
|
|
|
jni::init(vm);
|
|
|
|
try {
|
2022-10-04 02:58:50 +00:00
|
|
|
auto clazz = loadClassFromRuntimeApk((jobject)context, MonadoView::getFullyQualifiedTypeName());
|
2020-09-25 17:59:08 +00:00
|
|
|
if (clazz.isNull()) {
|
2022-08-30 15:41:41 +00:00
|
|
|
U_LOG_E("Could not load class '%s' from package '%s'", MonadoView::getFullyQualifiedTypeName(),
|
2021-01-14 14:13:48 +00:00
|
|
|
XRT_ANDROID_PACKAGE);
|
2020-09-25 17:59:08 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2020-09-08 20:09:07 +00:00
|
|
|
|
2020-10-28 16:50:10 +00:00
|
|
|
// Teach the wrapper our class before we start to use it.
|
|
|
|
MonadoView::staticInitClass((jclass)clazz.object().getHandle());
|
2022-10-04 02:58:50 +00:00
|
|
|
std::unique_ptr<android_custom_surface> ret = std::make_unique<android_custom_surface>();
|
2020-10-28 16:50:10 +00:00
|
|
|
|
2020-10-26 23:22:57 +00:00
|
|
|
// the 0 is to avoid this being considered "temporary" and to
|
|
|
|
// create a global ref.
|
2021-01-14 14:13:48 +00:00
|
|
|
ret->monadoViewClass = jni::Class((jclass)clazz.object().getHandle(), 0);
|
2020-09-25 17:59:08 +00:00
|
|
|
|
|
|
|
if (ret->monadoViewClass.isNull()) {
|
|
|
|
U_LOG_E("monadoViewClass was null");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string clazz_name = ret->monadoViewClass.getName();
|
2022-08-30 15:41:41 +00:00
|
|
|
if (clazz_name != MonadoView::getFullyQualifiedTypeName()) {
|
2021-01-14 14:13:48 +00:00
|
|
|
U_LOG_E("Unexpected class name: %s", clazz_name.c_str());
|
2020-09-25 17:59:08 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2022-10-04 02:58:50 +00:00
|
|
|
Context ctx = Context((jobject)context);
|
|
|
|
Context displayContext;
|
|
|
|
int32_t type = 0;
|
|
|
|
// Not focusable
|
|
|
|
int32_t flags =
|
|
|
|
WindowManager_LayoutParams::FLAG_FULLSCREEN() | WindowManager_LayoutParams::FLAG_NOT_FOCUSABLE();
|
|
|
|
|
|
|
|
if (android_globals_is_instance_of_activity(android_globals_get_vm(), context)) {
|
|
|
|
displayContext = ctx;
|
|
|
|
type = WindowManager_LayoutParams::TYPE_APPLICATION();
|
|
|
|
} else {
|
|
|
|
// Out of process mode, determine which display should be used.
|
|
|
|
DisplayManager dm = DisplayManager(ctx.getSystemService(Context::DISPLAY_SERVICE()));
|
|
|
|
Display display = dm.getDisplay(display_id);
|
|
|
|
displayContext = ctx.createDisplayContext(display);
|
|
|
|
type = WindowManager_LayoutParams::TYPE_APPLICATION_OVERLAY();
|
|
|
|
}
|
|
|
|
|
|
|
|
WindowManager_LayoutParams lp = WindowManager_LayoutParams::construct(type, flags);
|
|
|
|
ret->monadoView = MonadoView::attachToWindow(displayContext, ret.get(), lp);
|
2020-09-08 20:09:07 +00:00
|
|
|
|
|
|
|
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
|
2021-01-14 14:13:48 +00:00
|
|
|
android_custom_surface_destroy(struct android_custom_surface **ptr_custom_surface)
|
2020-09-08 20:09:07 +00:00
|
|
|
{
|
|
|
|
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 *
|
2021-01-14 14:13:48 +00:00
|
|
|
android_custom_surface_wait_get_surface(struct android_custom_surface *custom_surface, uint64_t timeout_ms)
|
2020-09-08 20:09:07 +00:00
|
|
|
{
|
2020-10-28 16:50:10 +00:00
|
|
|
SurfaceHolder surfaceHolder{};
|
2020-10-20 21:11:37 +00:00
|
|
|
try {
|
2021-01-14 14:13:48 +00:00
|
|
|
surfaceHolder = custom_surface->monadoView.waitGetSurfaceHolder(timeout_ms);
|
2020-10-26 23:22:57 +00:00
|
|
|
|
2020-10-20 21:11:37 +00:00
|
|
|
} catch (std::exception const &e) {
|
2020-10-26 23:22:57 +00:00
|
|
|
// do nothing right now.
|
|
|
|
U_LOG_E(
|
|
|
|
"Could not wait for our custom surface: "
|
|
|
|
"%s",
|
|
|
|
e.what());
|
2020-09-08 20:09:07 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
2020-10-20 21:11:37 +00:00
|
|
|
|
2020-10-26 23:22:57 +00:00
|
|
|
if (surfaceHolder.isNull()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2020-09-08 20:09:07 +00:00
|
|
|
auto surf = surfaceHolder.getSurface();
|
|
|
|
if (surf.isNull()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-01-14 14:13:48 +00:00
|
|
|
return ANativeWindow_fromSurface(jni::env(), surf.object().makeLocalReference());
|
2020-09-08 20:09:07 +00:00
|
|
|
}
|
2020-11-27 14:42:11 +00:00
|
|
|
|
|
|
|
bool
|
2021-01-14 14:13:48 +00:00
|
|
|
android_custom_surface_get_display_metrics(struct _JavaVM *vm,
|
2022-08-31 08:59:30 +00:00
|
|
|
void *context,
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_android_display_metrics *out_metrics)
|
2020-11-27 14:42:11 +00:00
|
|
|
{
|
|
|
|
jni::init(vm);
|
2022-08-31 08:59:30 +00:00
|
|
|
|
2020-11-27 14:42:11 +00:00
|
|
|
try {
|
2022-08-31 08:59:30 +00:00
|
|
|
auto clazz = loadClassFromRuntimeApk((jobject)context, MonadoView::getFullyQualifiedTypeName());
|
2020-11-27 14:42:11 +00:00
|
|
|
if (clazz.isNull()) {
|
2022-08-30 15:41:41 +00:00
|
|
|
U_LOG_E("Could not load class '%s' from package '%s'", MonadoView::getFullyQualifiedTypeName(),
|
2021-01-14 14:13:48 +00:00
|
|
|
XRT_ANDROID_PACKAGE);
|
2020-11-27 14:42:11 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Teach the wrapper our class before we start to use it.
|
|
|
|
MonadoView::staticInitClass((jclass)clazz.object().getHandle());
|
|
|
|
|
2022-08-31 08:59:30 +00:00
|
|
|
jni::Object displayMetrics = MonadoView::getDisplayMetrics(Context((jobject)context));
|
2022-03-22 12:33:30 +00:00
|
|
|
//! @todo implement non-deprecated codepath for api 30+
|
2022-08-31 08:59:30 +00:00
|
|
|
float displayRefreshRate = MonadoView::getDisplayRefreshRate(Context((jobject)context));
|
2022-03-22 12:33:30 +00:00
|
|
|
if (displayRefreshRate == 0.0) {
|
|
|
|
displayRefreshRate = 60.0f;
|
|
|
|
}
|
2021-01-14 14:13:48 +00:00
|
|
|
|
|
|
|
*out_metrics = {.width_pixels = displayMetrics.get<int>("widthPixels"),
|
|
|
|
.height_pixels = displayMetrics.get<int>("heightPixels"),
|
|
|
|
.density_dpi = displayMetrics.get<int>("densityDpi"),
|
|
|
|
.density = displayMetrics.get<float>("xdpi"),
|
|
|
|
.scaled_density = displayMetrics.get<float>("ydpi"),
|
|
|
|
.xdpi = displayMetrics.get<float>("density"),
|
2022-03-22 12:33:30 +00:00
|
|
|
.ydpi = displayMetrics.get<float>("scaledDensity"),
|
|
|
|
.refresh_rate = displayRefreshRate};
|
2020-11-27 14:42:11 +00:00
|
|
|
return true;
|
|
|
|
} catch (std::exception const &e) {
|
|
|
|
U_LOG_E("Could not get display metrics: %s", e.what());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|