diff --git a/src/xrt/auxiliary/android/android_custom_surface.cpp b/src/xrt/auxiliary/android/android_custom_surface.cpp index dc03ef642..1b1eaf094 100644 --- a/src/xrt/auxiliary/android/android_custom_surface.cpp +++ b/src/xrt/auxiliary/android/android_custom_surface.cpp @@ -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 - -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 ret = - std::make_unique((jobject)activity); + std::unique_ptr ret = std::make_unique(); // 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) { diff --git a/src/xrt/auxiliary/android/android_custom_surface.h b/src/xrt/auxiliary/android/android_custom_surface.h index a82b3cd13..b57e6f839 100644 --- a/src/xrt/auxiliary/android/android_custom_surface.h +++ b/src/xrt/auxiliary/android/android_custom_surface.h @@ -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 * @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. diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp index bef0d651e..d5547c0af 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.cpp @@ -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( diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp index 001a592cf..b93de8895 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.hpp @@ -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; diff --git a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp index 682e4f48b..fd01a97ac 100644 --- a/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp +++ b/src/xrt/auxiliary/android/org.freedesktop.monado.auxiliary.impl.hpp @@ -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( - Meta::data().attachToActivity, activity.object(), - static_cast(reinterpret_cast(nativePointer)))); + Meta::data().attachToWindow, displayContext.object(), + static_cast(reinterpret_cast(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(Meta::data().attachToActivity1, activity.object())); + Meta::data().clazz().call(Meta::data().removeFromWindow, view.object()); } inline jni::Object diff --git a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java index f8dd21e64..00c637fb7 100644 --- a/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java +++ b/src/xrt/auxiliary/android/src/main/java/org/freedesktop/monado/auxiliary/MonadoView.java @@ -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. diff --git a/src/xrt/compositor/main/comp_window_android.c b/src/xrt/compositor/main/comp_window_android.c index 2522ec98f..e3d96fe56 100644 --- a/src/xrt/compositor/main/comp_window_android.c +++ b/src/xrt/compositor/main/comp_window_android.c @@ -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 "