aux/android: Refactor MonadoView

This commit is contained in:
Jarvis Huang 2022-10-04 10:58:50 +08:00 committed by Ryan Pavlik
parent 7c02d466e2
commit cf7e44b710
7 changed files with 136 additions and 111 deletions

View file

@ -9,42 +9,44 @@
*/ */
#include "android_custom_surface.h" #include "android_custom_surface.h"
#include "android_globals.h"
#include "android_load_class.hpp" #include "android_load_class.hpp"
#include "xrt/xrt_config_android.h" #include "xrt/xrt_config_android.h"
#include "util/u_logging.h" #include "util/u_logging.h"
#include "wrap/android.app.h"
#include "wrap/android.content.h" #include "wrap/android.content.h"
#include "wrap/android.hardware.display.h"
#include "wrap/android.view.h" #include "wrap/android.view.h"
#include "org.freedesktop.monado.auxiliary.hpp" #include "org.freedesktop.monado.auxiliary.hpp"
#include <android/native_window_jni.h> #include <android/native_window_jni.h>
using wrap::android::app::Activity;
using wrap::android::content::Context; using wrap::android::content::Context;
using wrap::android::hardware::display::DisplayManager;
using wrap::android::view::Display;
using wrap::android::view::SurfaceHolder; using wrap::android::view::SurfaceHolder;
using wrap::android::view::WindowManager_LayoutParams;
using wrap::org::freedesktop::monado::auxiliary::MonadoView; using wrap::org::freedesktop::monado::auxiliary::MonadoView;
using xrt::auxiliary::android::loadClassFromRuntimeApk; using xrt::auxiliary::android::loadClassFromRuntimeApk;
struct android_custom_surface struct android_custom_surface
{ {
explicit android_custom_surface(jobject act); explicit android_custom_surface();
~android_custom_surface(); ~android_custom_surface();
Activity activity{};
MonadoView monadoView{}; MonadoView monadoView{};
jni::Class monadoViewClass{}; jni::Class monadoViewClass{};
}; };
android_custom_surface::android_custom_surface(jobject act) : activity(act) {} android_custom_surface::android_custom_surface() {}
android_custom_surface::~android_custom_surface() android_custom_surface::~android_custom_surface()
{ {
// Tell Java that native code is done with this. // Tell Java that native code is done with this.
try { try {
MonadoView::removeFromWindow(monadoView);
if (!monadoView.isNull()) { if (!monadoView.isNull()) {
monadoView.markAsDiscardedByNative(); monadoView.markAsDiscardedByNative();
} }
@ -55,11 +57,11 @@ android_custom_surface::~android_custom_surface()
} }
struct android_custom_surface * struct android_custom_surface *
android_custom_surface_async_start(struct _JavaVM *vm, void *activity) android_custom_surface_async_start(struct _JavaVM *vm, void *context, int32_t display_id)
{ {
jni::init(vm); jni::init(vm);
try { try {
auto clazz = loadClassFromRuntimeApk((jobject)activity, MonadoView::getFullyQualifiedTypeName()); auto clazz = loadClassFromRuntimeApk((jobject)context, MonadoView::getFullyQualifiedTypeName());
if (clazz.isNull()) { if (clazz.isNull()) {
U_LOG_E("Could not load class '%s' from package '%s'", MonadoView::getFullyQualifiedTypeName(), U_LOG_E("Could not load class '%s' from package '%s'", MonadoView::getFullyQualifiedTypeName(),
XRT_ANDROID_PACKAGE); XRT_ANDROID_PACKAGE);
@ -68,8 +70,7 @@ android_custom_surface_async_start(struct _JavaVM *vm, void *activity)
// Teach the wrapper our class before we start to use it. // Teach the wrapper our class before we start to use it.
MonadoView::staticInitClass((jclass)clazz.object().getHandle()); MonadoView::staticInitClass((jclass)clazz.object().getHandle());
std::unique_ptr<android_custom_surface> ret = std::unique_ptr<android_custom_surface> ret = std::make_unique<android_custom_surface>();
std::make_unique<android_custom_surface>((jobject)activity);
// the 0 is to avoid this being considered "temporary" and to // the 0 is to avoid this being considered "temporary" and to
// create a global ref. // create a global ref.
@ -86,7 +87,26 @@ android_custom_surface_async_start(struct _JavaVM *vm, void *activity)
return nullptr; return nullptr;
} }
ret->monadoView = MonadoView::attachToActivity(ret->activity, ret.get()); 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);
return ret.release(); return ret.release();
} catch (std::exception const &e) { } catch (std::exception const &e) {
@ -99,7 +119,6 @@ android_custom_surface_async_start(struct _JavaVM *vm, void *activity)
} }
} }
void void
android_custom_surface_destroy(struct android_custom_surface **ptr_custom_surface) android_custom_surface_destroy(struct android_custom_surface **ptr_custom_surface)
{ {

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: BSL-1.0 // SPDX-License-Identifier: BSL-1.0
/*! /*!
* @file * @file
* @brief Functions for adding a new Surface to an activity and otherwise * @brief Functions for adding a new Surface to a window and otherwise
* interacting with an Android View. * interacting with an Android View.
* @author Ryan Pavlik <ryan.pavlik@collabora.com> * @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @ingroup aux_android * @ingroup aux_android
@ -36,7 +36,7 @@ struct xrt_android_display_metrics
}; };
/*! /*!
* Opaque type representing a custom surface added to an activity, and the async * Opaque type representing a custom surface added to a window, and the async
* operation to perform this adding. * operation to perform this adding.
* *
* @note You must keep this around for as long as you're using the surface. * @note You must keep this around for as long as you're using the surface.
@ -44,7 +44,7 @@ struct xrt_android_display_metrics
struct android_custom_surface; struct android_custom_surface;
/*! /*!
* Start adding a custom surface to an activity. * Start adding a custom surface to a window.
* *
* This is an asynchronous operation, so this creates an opaque pointer for you * This is an asynchronous operation, so this creates an opaque pointer for you
* to check on the results and maintain a reference to the result. * to check on the results and maintain a reference to the result.
@ -52,8 +52,8 @@ struct android_custom_surface;
* Uses org.freedesktop.monado.auxiliary.MonadoView * Uses org.freedesktop.monado.auxiliary.MonadoView
* *
* @param vm Java VM pointer * @param vm Java VM pointer
* @param activity An android.app.Activity jobject, cast to * @param context An android.content.Context jobject, cast to `void *`.
* `void *`. * @param display_id Id of the display that the surface is attached to.
* *
* @return An opaque handle for monitoring this operation and referencing the * @return An opaque handle for monitoring this operation and referencing the
* surface, or NULL if there was an error. * surface, or NULL if there was an error.
@ -61,7 +61,7 @@ struct android_custom_surface;
* @public @memberof android_custom_surface * @public @memberof android_custom_surface
*/ */
struct android_custom_surface * struct android_custom_surface *
android_custom_surface_async_start(struct _JavaVM *vm, void *activity); android_custom_surface_async_start(struct _JavaVM *vm, void *context, int32_t display_id);
/*! /*!
* Destroy the native handle for the custom surface. * Destroy the native handle for the custom surface.

View file

@ -14,10 +14,12 @@ namespace wrap {
namespace org::freedesktop::monado::auxiliary { namespace org::freedesktop::monado::auxiliary {
MonadoView::Meta::Meta(jni::jclass clazz) MonadoView::Meta::Meta(jni::jclass clazz)
: MetaBase(MonadoView::getTypeName(), clazz), : MetaBase(MonadoView::getTypeName(), clazz),
attachToActivity(classRef().getStaticMethod( attachToWindow(classRef().getStaticMethod(
"attachToActivity", "(Landroid/app/Activity;J)Lorg/freedesktop/monado/auxiliary/MonadoView;")), "attachToWindow",
attachToActivity1(classRef().getStaticMethod( "(Landroid/content/Context;JLandroid/view/WindowManager$LayoutParams;)Lorg/freedesktop/monado/"
"attachToActivity", "(Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/MonadoView;")), "auxiliary/MonadoView;")),
removeFromWindow(
classRef().getStaticMethod("removeFromWindow", "(Lorg/freedesktop/monado/auxiliary/MonadoView;)V")),
getDisplayMetrics(classRef().getStaticMethod("getDisplayMetrics", getDisplayMetrics(classRef().getStaticMethod("getDisplayMetrics",
"(Landroid/content/Context;)Landroid/util/DisplayMetrics;")), "(Landroid/content/Context;)Landroid/util/DisplayMetrics;")),
getDisplayRefreshRate( getDisplayRefreshRate(

View file

@ -23,6 +23,7 @@ namespace android::content {
namespace android::view { namespace android::view {
class SurfaceHolder; class SurfaceHolder;
class WindowManager_LayoutParams;
} // namespace android::view } // namespace android::view
namespace org::freedesktop::monado::auxiliary { namespace org::freedesktop::monado::auxiliary {
@ -54,29 +55,33 @@ namespace org::freedesktop::monado::auxiliary {
} }
/*! /*!
* Wrapper for the attachToActivity static method * Wrapper for the attachToWindow static method
* *
* Java prototype: * Java prototype:
* `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.app.Activity, * `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.content.Context,
* long);` * long, android.view.WindowManager.LayoutParams);`
* *
* JNI signature: (Landroid/app/Activity;J)Lorg/freedesktop/monado/auxiliary/MonadoView; * JNI signature:
* (Landroid/content/Context;JLandroid/view/WindowManager$LayoutParams;)Lorg/freedesktop/monado/auxiliary/MonadoView;
* *
*/ */
static MonadoView static MonadoView
attachToActivity(android::app::Activity const &activity, void *nativePointer); attachToWindow(android::content::Context const &displayContext,
void *nativePointer,
android::view::WindowManager_LayoutParams const &lp);
/*! /*!
* Wrapper for the attachToActivity static method * Wrapper for the removeFromWindow static method
* *
* Java prototype: * Java prototype:
* `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.app.Activity);` * `public static void removeFromWindow(android.content.Context,
* org.freedesktop.monado.auxiliary.MonadoView, int);`
* *
* JNI signature: (Landroid/app/Activity;)Lorg/freedesktop/monado/auxiliary/MonadoView; * JNI signature: (Landroid/content/Context;Lorg/freedesktop/monado/auxiliary/MonadoView;I)V
* *
*/ */
static MonadoView static void
attachToActivity(android::app::Activity const &activity); removeFromWindow(MonadoView const &view);
/*! /*!
* Wrapper for the getDisplayMetrics static method * Wrapper for the getDisplayMetrics static method
@ -153,8 +158,8 @@ namespace org::freedesktop::monado::auxiliary {
*/ */
struct Meta : public MetaBase struct Meta : public MetaBase
{ {
jni::method_t attachToActivity; jni::method_t attachToWindow;
jni::method_t attachToActivity1; jni::method_t removeFromWindow;
jni::method_t getDisplayMetrics; jni::method_t getDisplayMetrics;
jni::method_t getDisplayRefreshRate; jni::method_t getDisplayRefreshRate;
jni::method_t getNativePointer; jni::method_t getNativePointer;

View file

@ -18,18 +18,19 @@
namespace wrap { namespace wrap {
namespace org::freedesktop::monado::auxiliary { namespace org::freedesktop::monado::auxiliary {
inline MonadoView inline MonadoView
MonadoView::attachToActivity(android::app::Activity const &activity, void *nativePointer) MonadoView::attachToWindow(android::content::Context const &displayContext,
void *nativePointer,
wrap::android::view::WindowManager_LayoutParams const &lp)
{ {
return MonadoView(Meta::data().clazz().call<jni::Object>( return MonadoView(Meta::data().clazz().call<jni::Object>(
Meta::data().attachToActivity, activity.object(), Meta::data().attachToWindow, displayContext.object(),
static_cast<long long>(reinterpret_cast<uintptr_t>(nativePointer)))); static_cast<long long>(reinterpret_cast<uintptr_t>(nativePointer)), lp.object()));
} }
inline MonadoView inline void
MonadoView::attachToActivity(android::app::Activity const &activity) MonadoView::removeFromWindow(const MonadoView &view)
{ {
return MonadoView( Meta::data().clazz().call<void>(Meta::data().removeFromWindow, view.object());
Meta::data().clazz().call<jni::Object>(Meta::data().attachToActivity1, activity.object()));
} }
inline jni::Object inline jni::Object

View file

@ -11,7 +11,8 @@ package org.freedesktop.monado.auxiliary;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Build; import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.Log; import android.util.Log;
@ -29,10 +30,6 @@ public class MonadoView extends SurfaceView
implements SurfaceHolder.Callback, SurfaceHolder.Callback2 { implements SurfaceHolder.Callback, SurfaceHolder.Callback2 {
private static final String TAG = "MonadoView"; private static final String TAG = "MonadoView";
@NonNull private final Context context;
/// The activity we've connected to.
@Nullable private final Activity activity;
private final Object currentSurfaceHolderSync = new Object(); private final Object currentSurfaceHolderSync = new Object();
public int width = -1; public int width = -1;
@ -47,28 +44,19 @@ public class MonadoView extends SurfaceView
public MonadoView(Context context) { public MonadoView(Context context) {
super(context); super(context);
this.context = context;
Activity activity;
if (context instanceof Activity) { if (context instanceof Activity) {
activity = (Activity) context; Activity activity = (Activity) context;
systemUiController = new SystemUiController(activity.getWindow().getDecorView()); systemUiController = new SystemUiController(activity.getWindow().getDecorView());
systemUiController.hide(); systemUiController.hide();
} else {
activity = null;
} }
this.activity = activity; SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
} }
public MonadoView(Activity activity) { private MonadoView(Context context, long nativePointer) {
super(activity); this(context);
this.context = activity;
this.activity = activity;
systemUiController = new SystemUiController(activity.getWindow().getDecorView());
systemUiController.hide();
}
private MonadoView(Activity activity, long nativePointer) {
this(activity);
nativeCounterpart = new NativeCounterpart(nativePointer); nativeCounterpart = new NativeCounterpart(nativePointer);
} }
@ -76,25 +64,73 @@ public class MonadoView extends SurfaceView
* Construct and start attaching a MonadoView to a client application. * Construct and start attaching a MonadoView to a client application.
* *
* @param activity The activity to attach to. * @param activity The activity to attach to.
* @param nativePointer The native android_custom_surface pointer, cast to a long.
* @return The MonadoView instance created and asynchronously attached. * @return The MonadoView instance created and asynchronously attached.
*/ */
@NonNull @Keep @NonNull @Keep
@SuppressWarnings("deprecation") public static MonadoView attachToActivity(@NonNull final Activity activity) {
public static MonadoView attachToActivity( final MonadoView view = new MonadoView(activity);
@NonNull final Activity activity, long nativePointer) { WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
final MonadoView view = new MonadoView(activity, nativePointer); lp.flags =
view.createSurfaceInActivity(); WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
attachToWindow(activity, view, lp);
return view; return view;
} }
/**
* Construct and start attaching a MonadoView to window.
*
* @param displayContext Display context used for looking for target window.
* @param nativePointer The native android_custom_surface pointer, cast to a long.
* @param lp Layout parameters associated with view.
* @return The MonadoView instance created and asynchronously attached.
*/
@NonNull @Keep @NonNull @Keep
public static MonadoView attachToActivity(@NonNull final Activity activity) { public static MonadoView attachToWindow(
final MonadoView view = new MonadoView(activity); @NonNull final Context displayContext,
view.createSurfaceInActivity(); long nativePointer,
WindowManager.LayoutParams lp)
throws IllegalArgumentException {
final MonadoView view = new MonadoView(displayContext, nativePointer);
attachToWindow(displayContext, view, lp);
return view; return view;
} }
private static void attachToWindow(
@NonNull final Context context,
@NonNull MonadoView view,
@NonNull WindowManager.LayoutParams lp) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
() -> {
Log.d(TAG, "Start adding view to window");
WindowManager wm =
(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.addView(view, lp);
SystemUiController systemUiController = new SystemUiController(view);
systemUiController.hide();
});
}
/**
* Remove given MonadoView from window.
*
* @param view The view to remove.
*/
@Keep
public static void removeFromWindow(@NonNull MonadoView view) {
Handler handler = new Handler(Looper.getMainLooper());
handler.post(
() -> {
Log.d(TAG, "Start removing view from window");
WindowManager wm =
(WindowManager)
view.getContext().getSystemService(Context.WINDOW_SERVICE);
wm.removeView(view);
});
}
@NonNull @Keep @NonNull @Keep
public static DisplayMetrics getDisplayMetrics(@NonNull Context context) { public static DisplayMetrics getDisplayMetrics(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics(); DisplayMetrics displayMetrics = new DisplayMetrics();
@ -117,45 +153,6 @@ public class MonadoView extends SurfaceView
return nativeCounterpart.getNativePointer(); return nativeCounterpart.getNativePointer();
} }
private void createSurfaceInActivity() {
createSurfaceInActivity(false);
}
/** @param focusable Indicates MonadoView should be focusable or not */
private void createSurfaceInActivity(boolean focusable) {
Log.i(TAG, "Starting to add a new surface!");
activity.runOnUiThread(
() -> {
Log.i(TAG, "Starting runOnUiThread");
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
WindowManager windowManager = activity.getWindowManager();
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
if (focusable) {
lp.flags = WindowManager.LayoutParams.FLAG_FULLSCREEN;
} else {
// There are 2 problems if view is focusable on all-in-one device:
// 1. Navigation bar won't go away because view gets focus.
// 2. Underlying activity lost focus and cannot receive input.
lp.flags =
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
lp.layoutInDisplayCutoutMode =
WindowManager.LayoutParams
.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
}
windowManager.addView(this, lp);
if (focusable) {
requestFocus();
}
SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
Log.i(TAG, "Registered callbacks!");
});
}
/** /**
* Block up to a specified amount of time, waiting for the surfaceCreated callback to be fired * Block up to a specified amount of time, waiting for the surfaceCreated callback to be fired
* and populate the currentSurfaceHolder. * and populate the currentSurfaceHolder.

View file

@ -87,8 +87,9 @@ comp_window_android_update_window_title(struct comp_target *ct, const char *titl
static struct ANativeWindow * static struct ANativeWindow *
_create_android_window(struct comp_window_android *cwa) _create_android_window(struct comp_window_android *cwa)
{ {
// 0 means default display
cwa->custom_surface = cwa->custom_surface =
android_custom_surface_async_start(android_globals_get_vm(), android_globals_get_activity()); android_custom_surface_async_start(android_globals_get_vm(), android_globals_get_activity(), 0);
if (cwa->custom_surface == NULL) { if (cwa->custom_surface == NULL) {
COMP_ERROR(cwa->base.base.c, COMP_ERROR(cwa->base.base.c,
"comp_window_android_create_surface: could not " "comp_window_android_create_surface: could not "