mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-16 11:55:39 +00:00
comp/android: Refine surface creation flow
Reuse MonadoView when "Display over other apps" is enabled. Move surface creation logic to compositor for consistency. With this approach, compositor implementer controls the way surface is created.
This commit is contained in:
parent
cf7e44b710
commit
0d31791092
1
doc/changes/compositor/mr.1742.md
Normal file
1
doc/changes/compositor/mr.1742.md
Normal file
|
@ -0,0 +1 @@
|
|||
Android: Refactor surface creation flow.
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "wrap/android.content.h"
|
||||
#include "wrap/android.hardware.display.h"
|
||||
#include "wrap/android.provider.h"
|
||||
#include "wrap/android.view.h"
|
||||
#include "org.freedesktop.monado.auxiliary.hpp"
|
||||
|
||||
|
@ -24,6 +25,7 @@
|
|||
|
||||
using wrap::android::content::Context;
|
||||
using wrap::android::hardware::display::DisplayManager;
|
||||
using wrap::android::provider::Settings;
|
||||
using wrap::android::view::Display;
|
||||
using wrap::android::view::SurfaceHolder;
|
||||
using wrap::android::view::WindowManager_LayoutParams;
|
||||
|
@ -198,3 +200,10 @@ android_custom_surface_get_display_metrics(struct _JavaVM *vm,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
android_custom_surface_can_draw_overlays(struct _JavaVM *vm, void *context)
|
||||
{
|
||||
jni::init(vm);
|
||||
return Settings::canDrawOverlays(Context{(jobject)context});
|
||||
}
|
||||
|
|
|
@ -93,6 +93,9 @@ android_custom_surface_get_display_metrics(struct _JavaVM *vm,
|
|||
void *activity,
|
||||
struct xrt_android_display_metrics *out_metrics);
|
||||
|
||||
bool
|
||||
android_custom_surface_can_draw_overlays(struct _JavaVM *vm, void *context);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -89,7 +89,7 @@ _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(), 0);
|
||||
android_custom_surface_async_start(android_globals_get_vm(), android_globals_get_context(), 0);
|
||||
if (cwa->custom_surface == NULL) {
|
||||
COMP_ERROR(cwa->base.base.c,
|
||||
"comp_window_android_create_surface: could not "
|
||||
|
@ -138,11 +138,14 @@ comp_window_android_init_swapchain(struct comp_target *ct, uint32_t width, uint3
|
|||
if (android_globals_get_activity() != NULL) {
|
||||
/* In process: Creating surface from activity */
|
||||
window = _create_android_window(cwa);
|
||||
} else if (android_custom_surface_can_draw_overlays(android_globals_get_vm(), android_globals_get_context())) {
|
||||
/* Out of process: Create surface */
|
||||
window = _create_android_window(cwa);
|
||||
} else {
|
||||
/* Out of process: Getting cached surface.
|
||||
* This loop polls for a surface created by Client.java in blockingConnect.
|
||||
* TODO: change java code to callback native code to notify Session lifecycle progress, instead of
|
||||
* polling here
|
||||
* TODO: change java code to callback native code to notify Session lifecycle progress, instead
|
||||
* of polling here
|
||||
*/
|
||||
for (int i = 0; i < 100; i++) {
|
||||
window = (struct ANativeWindow *)android_globals_get_window();
|
||||
|
@ -152,6 +155,7 @@ comp_window_android_init_swapchain(struct comp_target *ct, uint32_t width, uint3
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (window == NULL) {
|
||||
COMP_ERROR(cwa->base.base.c, "could not get ANativeWindow");
|
||||
return false;
|
||||
|
|
|
@ -23,11 +23,6 @@ interface IMonado {
|
|||
*/
|
||||
void passAppSurface(in Surface surface);
|
||||
|
||||
/*!
|
||||
* Asking service to create surface and attach it to the display matches given display id.
|
||||
*/
|
||||
boolean createSurface(int displayId, boolean focusable);
|
||||
|
||||
/*!
|
||||
* Asking service whether it has the capbility to draw over other apps or not.
|
||||
*/
|
||||
|
|
|
@ -22,7 +22,6 @@ import android.os.RemoteException;
|
|||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.Nullable;
|
||||
|
@ -155,41 +154,26 @@ public class Client implements ServiceConnection {
|
|||
// (ready ... synchronized ... visible ... focused)
|
||||
new Thread(
|
||||
() -> {
|
||||
boolean surfaceCreated = false;
|
||||
Activity activity = null;
|
||||
if (context_ instanceof Activity) {
|
||||
activity = (Activity) context_;
|
||||
}
|
||||
|
||||
try {
|
||||
// Determine whether runtime or client should create surface
|
||||
if (monado.canDrawOverOtherApps()) {
|
||||
WindowManager wm =
|
||||
(WindowManager)
|
||||
context_.getSystemService(
|
||||
Context.WINDOW_SERVICE);
|
||||
surfaceCreated =
|
||||
monado.createSurface(
|
||||
wm.getDefaultDisplay().getDisplayId(), false);
|
||||
} else {
|
||||
if (activity != null) {
|
||||
Surface surface = attachViewAndGetSurface(activity);
|
||||
surfaceCreated = (surface != null);
|
||||
if (surfaceCreated) {
|
||||
monado.passAppSurface(surface);
|
||||
}
|
||||
if (!monado.canDrawOverOtherApps() && activity != null) {
|
||||
Surface surface = attachViewAndGetSurface(activity);
|
||||
if (surface == null) {
|
||||
Log.e(TAG, "Failed to create surface");
|
||||
handleFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
monado.passAppSurface(surface);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (!surfaceCreated) {
|
||||
Log.e(TAG, "Failed to create surface");
|
||||
handleFailure();
|
||||
return;
|
||||
}
|
||||
|
||||
if (activity != null) {
|
||||
systemUiController =
|
||||
new SystemUiController(activity.getWindow().getDecorView());
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
|
||||
package org.freedesktop.monado.ipc;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.ParcelFileDescriptor;
|
||||
import android.os.RemoteException;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -40,30 +41,15 @@ public class MonadoImpl extends IMonado.Stub {
|
|||
System.loadLibrary("monado-service");
|
||||
}
|
||||
|
||||
private SurfaceManager surfaceManager;
|
||||
private final Context context;
|
||||
|
||||
public MonadoImpl(@NonNull SurfaceManager surfaceManager) {
|
||||
this.surfaceManager = surfaceManager;
|
||||
this.surfaceManager.setCallback(
|
||||
new SurfaceHolder.Callback() {
|
||||
@Override
|
||||
public void surfaceCreated(@NonNull SurfaceHolder holder) {
|
||||
Log.i(TAG, "surfaceCreated");
|
||||
passAppSurface(holder.getSurface());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(
|
||||
@NonNull SurfaceHolder holder, int format, int width, int height) {}
|
||||
|
||||
@Override
|
||||
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {}
|
||||
});
|
||||
public MonadoImpl(@NonNull Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
nativeStartServer(this.context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect(@NonNull ParcelFileDescriptor parcelFileDescriptor) throws RemoteException {
|
||||
nativeStartServer();
|
||||
int fd = parcelFileDescriptor.getFd();
|
||||
Log.i(TAG, "connect: given fd " + fd);
|
||||
if (nativeAddClient(fd) != 0) {
|
||||
|
@ -90,19 +76,12 @@ public class MonadoImpl extends IMonado.Stub {
|
|||
return;
|
||||
}
|
||||
nativeAppSurface(surface);
|
||||
nativeStartServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createSurface(int displayId, boolean focusable) {
|
||||
Log.i(TAG, "createSurface");
|
||||
return surfaceManager.createSurfaceOnDisplay(displayId, focusable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canDrawOverOtherApps() {
|
||||
Log.i(TAG, "canDrawOverOtherApps");
|
||||
return surfaceManager.canDrawOverlays();
|
||||
return Settings.canDrawOverlays(context);
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
|
@ -110,9 +89,17 @@ public class MonadoImpl extends IMonado.Stub {
|
|||
nativeShutdownServer();
|
||||
}
|
||||
|
||||
/** Native method that starts server. */
|
||||
/**
|
||||
* Native method that starts server.
|
||||
*
|
||||
* <p>This is essentially the entry point for the monado service on Android.
|
||||
*
|
||||
* <p>
|
||||
*
|
||||
* @param context Context object.
|
||||
*/
|
||||
@SuppressWarnings("JavaJniMissingFunction")
|
||||
private native void nativeStartServer();
|
||||
private native void nativeStartServer(@NonNull Context context);
|
||||
|
||||
/**
|
||||
* Native handling of receiving a surface: should convert it to an ANativeWindow then do stuff
|
||||
|
@ -131,10 +118,6 @@ public class MonadoImpl extends IMonado.Stub {
|
|||
* Native handling of receiving an FD for a new client: the FD should be used to start up the
|
||||
* rest of the native IPC code on that socket.
|
||||
*
|
||||
* <p>This is essentially the entry point for the monado service on Android: if it's already
|
||||
* running, this will be called in it. If it's not already running, a process will be created,
|
||||
* and this will be the first native code executed in that process.
|
||||
*
|
||||
* <p>Ignore warnings that this function is missing: it is not, it is just in a different
|
||||
* module. See `src/xrt/targets/service-lib/service_target.cpp` for the implementation.
|
||||
*
|
||||
|
|
|
@ -32,19 +32,15 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
|
|||
|
||||
@Inject lateinit var serviceNotification: IServiceNotification
|
||||
|
||||
private lateinit var surfaceManager: SurfaceManager
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
surfaceManager = SurfaceManager(this)
|
||||
binder = MonadoImpl(surfaceManager)
|
||||
binder = MonadoImpl(this)
|
||||
watchdog =
|
||||
Watchdog(
|
||||
// If the surface comes from client, just stop the service when client disconnected
|
||||
// because the surface belongs to the client.
|
||||
if (surfaceManager.canDrawOverlays()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS
|
||||
else 0,
|
||||
if (binder.canDrawOverOtherApps()) BuildConfig.WATCHDOG_TIMEOUT_MILLISECONDS else 0,
|
||||
this
|
||||
)
|
||||
watchdog.startMonitor()
|
||||
|
@ -61,7 +57,6 @@ class MonadoService : Service(), Watchdog.ShutdownListener {
|
|||
|
||||
binder.shutdown()
|
||||
watchdog.stopMonitor()
|
||||
surfaceManager.destroySurface()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
|
|
|
@ -8,25 +8,9 @@
|
|||
package org.freedesktop.monado.openxr_runtime;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import dagger.hilt.android.HiltAndroidApp;
|
||||
|
||||
/** Subclass required for Hilt usage. */
|
||||
@HiltAndroidApp
|
||||
public class MonadoOpenXrApplication extends Application {
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
if (!BuildConfig.inProcess) {
|
||||
System.loadLibrary("monado-service");
|
||||
nativeStoreContext(getApplicationContext());
|
||||
}
|
||||
}
|
||||
|
||||
private native void nativeStoreContext(@NonNull Context context);
|
||||
}
|
||||
public class MonadoOpenXrApplication extends Application {}
|
||||
|
|
|
@ -133,13 +133,20 @@ private:
|
|||
};
|
||||
} // namespace
|
||||
|
||||
extern "C" void
|
||||
Java_org_freedesktop_monado_ipc_MonadoImpl_nativeStartServer(JNIEnv *env, jobject thiz)
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_freedesktop_monado_ipc_MonadoImpl_nativeStartServer(JNIEnv *env, jobject thiz, jobject context)
|
||||
{
|
||||
JavaVM *jvm = nullptr;
|
||||
jint result = env->GetJavaVM(&jvm);
|
||||
assert(result == JNI_OK);
|
||||
assert(jvm);
|
||||
|
||||
jni::init(env);
|
||||
jni::Object monadoImpl(thiz);
|
||||
U_LOG_D("service: Called nativeStartServer");
|
||||
|
||||
android_globals_store_vm_and_context(jvm, context);
|
||||
|
||||
IpcServerHelper::instance().startServer();
|
||||
}
|
||||
|
||||
|
@ -174,17 +181,3 @@ Java_org_freedesktop_monado_ipc_MonadoImpl_nativeShutdownServer(JNIEnv *env, job
|
|||
|
||||
return IpcServerHelper::instance().shutdownServer();
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_freedesktop_monado_openxr_1runtime_MonadoOpenXrApplication_nativeStoreContext(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jobject context)
|
||||
{
|
||||
JavaVM *jvm = nullptr;
|
||||
jint result = env->GetJavaVM(&jvm);
|
||||
assert(result == JNI_OK);
|
||||
assert(jvm);
|
||||
|
||||
jni::init(env);
|
||||
android_globals_store_vm_and_context(jvm, context);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue