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_globals.h"
#include "android_load_class.hpp"
#include "xrt/xrt_config_android.h"
#include "util/u_logging.h"
#include "wrap/android.app.h"
#include "wrap/android.content.h"
#include "wrap/android.hardware.display.h"
#include "wrap/android.view.h"
#include "org.freedesktop.monado.auxiliary.hpp"
#include <android/native_window_jni.h>
using wrap::android::app::Activity;
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::WindowManager_LayoutParams;
using wrap::org::freedesktop::monado::auxiliary::MonadoView;
using xrt::auxiliary::android::loadClassFromRuntimeApk;
struct android_custom_surface
{
explicit android_custom_surface(jobject act);
explicit android_custom_surface();
~android_custom_surface();
Activity activity{};
MonadoView monadoView{};
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()
{
// Tell Java that native code is done with this.
try {
MonadoView::removeFromWindow(monadoView);
if (!monadoView.isNull()) {
monadoView.markAsDiscardedByNative();
}
@ -55,11 +57,11 @@ android_custom_surface::~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);
try {
auto clazz = loadClassFromRuntimeApk((jobject)activity, MonadoView::getFullyQualifiedTypeName());
auto clazz = loadClassFromRuntimeApk((jobject)context, MonadoView::getFullyQualifiedTypeName());
if (clazz.isNull()) {
U_LOG_E("Could not load class '%s' from package '%s'", MonadoView::getFullyQualifiedTypeName(),
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.
MonadoView::staticInitClass((jclass)clazz.object().getHandle());
std::unique_ptr<android_custom_surface> ret =
std::make_unique<android_custom_surface>((jobject)activity);
std::unique_ptr<android_custom_surface> ret = std::make_unique<android_custom_surface>();
// the 0 is to avoid this being considered "temporary" and to
// create a global ref.
@ -86,7 +87,26 @@ android_custom_surface_async_start(struct _JavaVM *vm, void *activity)
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();
} catch (std::exception const &e) {
@ -99,7 +119,6 @@ android_custom_surface_async_start(struct _JavaVM *vm, void *activity)
}
}
void
android_custom_surface_destroy(struct android_custom_surface **ptr_custom_surface)
{

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: BSL-1.0
/*!
* @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.
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
* @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.
*
* @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;
/*!
* 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
* 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
*
* @param vm Java VM pointer
* @param activity An android.app.Activity jobject, cast to
* `void *`.
* @param context An android.content.Context jobject, cast to `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
* surface, or NULL if there was an error.
@ -61,7 +61,7 @@ struct android_custom_surface;
* @public @memberof 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.

View file

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

View file

@ -23,6 +23,7 @@ namespace android::content {
namespace android::view {
class SurfaceHolder;
class WindowManager_LayoutParams;
} // namespace android::view
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:
* `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.app.Activity,
* long);`
* `public static org.freedesktop.monado.auxiliary.MonadoView attachToActivity(android.content.Context,
* 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
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:
* `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
attachToActivity(android::app::Activity const &activity);
static void
removeFromWindow(MonadoView const &view);
/*!
* Wrapper for the getDisplayMetrics static method
@ -153,8 +158,8 @@ namespace org::freedesktop::monado::auxiliary {
*/
struct Meta : public MetaBase
{
jni::method_t attachToActivity;
jni::method_t attachToActivity1;
jni::method_t attachToWindow;
jni::method_t removeFromWindow;
jni::method_t getDisplayMetrics;
jni::method_t getDisplayRefreshRate;
jni::method_t getNativePointer;

View file

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

View file

@ -11,7 +11,8 @@ package org.freedesktop.monado.auxiliary;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.DisplayMetrics;
import android.util.Log;
@ -29,10 +30,6 @@ public class MonadoView extends SurfaceView
implements SurfaceHolder.Callback, SurfaceHolder.Callback2 {
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();
public int width = -1;
@ -47,28 +44,19 @@ public class MonadoView extends SurfaceView
public MonadoView(Context context) {
super(context);
this.context = context;
Activity activity;
if (context instanceof Activity) {
activity = (Activity) context;
Activity activity = (Activity) context;
systemUiController = new SystemUiController(activity.getWindow().getDecorView());
systemUiController.hide();
} else {
activity = null;
}
this.activity = activity;
SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(this);
}
public MonadoView(Activity activity) {
super(activity);
this.context = activity;
this.activity = activity;
systemUiController = new SystemUiController(activity.getWindow().getDecorView());
systemUiController.hide();
}
private MonadoView(Context context, long nativePointer) {
this(context);
private MonadoView(Activity activity, long nativePointer) {
this(activity);
nativeCounterpart = new NativeCounterpart(nativePointer);
}
@ -76,25 +64,73 @@ public class MonadoView extends SurfaceView
* Construct and start attaching a MonadoView to a client application.
*
* @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.
*/
@NonNull @Keep
@SuppressWarnings("deprecation")
public static MonadoView attachToActivity(
@NonNull final Activity activity, long nativePointer) {
final MonadoView view = new MonadoView(activity, nativePointer);
view.createSurfaceInActivity();
public static MonadoView attachToActivity(@NonNull final Activity activity) {
final MonadoView view = new MonadoView(activity);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.flags =
WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
attachToWindow(activity, view, lp);
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
public static MonadoView attachToActivity(@NonNull final Activity activity) {
final MonadoView view = new MonadoView(activity);
view.createSurfaceInActivity();
public static MonadoView attachToWindow(
@NonNull final Context displayContext,
long nativePointer,
WindowManager.LayoutParams lp)
throws IllegalArgumentException {
final MonadoView view = new MonadoView(displayContext, nativePointer);
attachToWindow(displayContext, view, lp);
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
public static DisplayMetrics getDisplayMetrics(@NonNull Context context) {
DisplayMetrics displayMetrics = new DisplayMetrics();
@ -117,45 +153,6 @@ public class MonadoView extends SurfaceView
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
* 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 *
_create_android_window(struct comp_window_android *cwa)
{
// 0 means default display
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) {
COMP_ERROR(cwa->base.base.c,
"comp_window_android_create_surface: could not "