mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-06 07:06:10 +00:00
aux/android: Factor out a "native counterpart" class.
This commit is contained in:
parent
2082eddb65
commit
5115124bb3
|
@ -8,7 +8,7 @@ android {
|
|||
buildToolsVersion '30.0.2'
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 20
|
||||
minSdkVersion 24
|
||||
targetSdkVersion project.sharedTargetSdk
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
package org.freedesktop.monado.auxiliary;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
@ -19,6 +20,7 @@ import android.view.WindowManager;
|
|||
import androidx.annotation.Keep;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
@ -43,9 +45,8 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
|
||||
/// Guards currentSurfaceHolder
|
||||
private final Object currentSurfaceHolderSync = new Object();
|
||||
/// Guards the usedByNativeCode flag
|
||||
private final Object usedByNativeCodeSync = new Object();
|
||||
private final Method viewSetSysUiVis;
|
||||
private final NativeCounterpart nativeCounterpart;
|
||||
|
||||
public int width = -1;
|
||||
public int height = -1;
|
||||
|
@ -53,15 +54,11 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
|
||||
/// Guarded by currentSurfaceHolderSync
|
||||
private SurfaceHolder currentSurfaceHolder = null;
|
||||
/// Guarded by usedByNativeCodeSync
|
||||
private boolean usedByNativeCode = false;
|
||||
/// Contains the pointer to the native android_custom_surface object.
|
||||
private long nativePointer = 0;
|
||||
|
||||
private MonadoView(Activity activity, long nativePointer) {
|
||||
super(activity);
|
||||
this.activity = activity;
|
||||
this.nativePointer = nativePointer;
|
||||
this.nativeCounterpart = new NativeCounterpart(nativePointer);
|
||||
Method method;
|
||||
try {
|
||||
method = activity.getWindow().getDecorView().getClass().getMethod("setSystemUiVisibility", int.class);
|
||||
|
@ -133,10 +130,7 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
}
|
||||
}
|
||||
if (ret != null) {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
usedByNativeCode = true;
|
||||
usedByNativeCodeSync.notifyAll();
|
||||
}
|
||||
nativeCounterpart.markAsUsedByNativeCode();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -149,16 +143,7 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
*/
|
||||
@Keep
|
||||
public void markAsDiscardedByNative() {
|
||||
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
if (!usedByNativeCode) {
|
||||
Log.w(TAG, "This should not have happened: Discarding by native code, but not marked as used!");
|
||||
}
|
||||
usedByNativeCode = false;
|
||||
nativePointer = 0;
|
||||
usedByNativeCodeSync.notifyAll();
|
||||
}
|
||||
|
||||
nativeCounterpart.markAsDiscardedByNative(TAG);
|
||||
}
|
||||
|
||||
private boolean makeFullscreen() {
|
||||
|
@ -184,6 +169,7 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
/**
|
||||
* Add a listener so that if our system UI display state doesn't include all we want, we re-apply.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.HONEYCOMB)
|
||||
@SuppressWarnings("deprecation")
|
||||
private void setSystemUiVisChangeListener() {
|
||||
activity.getWindow().getDecorView().setOnSystemUiVisibilityChangeListener(visibility -> {
|
||||
|
@ -234,16 +220,9 @@ public class MonadoView extends SurfaceView implements SurfaceHolder.Callback, S
|
|||
}
|
||||
if (lost) {
|
||||
//! @todo this function should notify native code that the surface is gone.
|
||||
try {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
while (usedByNativeCode) {
|
||||
usedByNativeCodeSync.wait();
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
if (!nativeCounterpart.blockUntilNativeDiscard(TAG)) {
|
||||
Log.i(TAG,
|
||||
"Interrupted in surfaceDestroyed while waiting for native code to finish up: " + e.toString());
|
||||
"Interrupted in surfaceDestroyed while waiting for native code to finish up.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
// Copyright 2020, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Utility class to deal with having a native-code counterpart object
|
||||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
* @ingroup aux_android_java
|
||||
*/
|
||||
|
||||
package org.freedesktop.monado.auxiliary;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
/**
|
||||
* Object that tracks the native counterpart object for a type. Must be initialized on construction,
|
||||
* and may have its native code destroyed/discarded, but may not "re-seat" it to new native code
|
||||
* pointer.
|
||||
* <p>
|
||||
* Use as a member of any type with a native counterpart (a native-allocated-and-owned object that
|
||||
* holds a reference to the owning class). Include the following field and delegating method to use
|
||||
* (note: assumes you have a tag for logging purposes as TAG)
|
||||
* <p>
|
||||
* <pre>
|
||||
* private final NativeCounterpart nativeCounterpart;
|
||||
*
|
||||
* @Keep
|
||||
* public void markAsDiscardedByNative() {
|
||||
* nativeCounterpart.markAsDiscardedByNative(TAG);
|
||||
* }
|
||||
* </pre>
|
||||
* Then, initialize it in your constructor, call {@code markAsUsedByNativeCode()} where desired
|
||||
* (often in your constructor), and call {@code getNativePointer()} and
|
||||
* {@code blockUntilNativeDiscard()} as needed.
|
||||
* <p>
|
||||
* Your native code can use this to turn a void* into a jlong:
|
||||
* {@code static_cast<long long>(reinterpret_cast<intptr_t>(nativePointer))}
|
||||
*/
|
||||
public final class NativeCounterpart {
|
||||
/**
|
||||
* Guards the usedByNativeCodeSync.
|
||||
*/
|
||||
private final Object usedByNativeCodeSync = new Object();
|
||||
|
||||
/**
|
||||
* Indicates if the containing object is in use by native code.
|
||||
* <p>
|
||||
* Guarded by usedByNativeCodeSync.
|
||||
*/
|
||||
private boolean usedByNativeCode = false;
|
||||
|
||||
/**
|
||||
* Contains the pointer to the native counterpart object.
|
||||
*/
|
||||
private long nativePointer = 0;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param nativePointer The native pointer, cast appropriately. Must be non-zero. Can cast like:
|
||||
* {@code static_cast<long long>(reinterpret_cast<intptr_t>(nativePointer))}
|
||||
*/
|
||||
public NativeCounterpart(long nativePointer) throws InvalidParameterException {
|
||||
if (nativePointer == 0) {
|
||||
throw new InvalidParameterException("nativePointer must not be 0");
|
||||
}
|
||||
this.nativePointer = nativePointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the flag to indicate that native code is using this. Only call this once, probably in
|
||||
* your constructor unless you have a good reason to call it elsewhere.
|
||||
*/
|
||||
public void markAsUsedByNativeCode() {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
assert nativePointer != 0;
|
||||
usedByNativeCode = true;
|
||||
usedByNativeCodeSync.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the flag and notify those waiting on it, to indicate that native code is done with
|
||||
* this object.
|
||||
*
|
||||
* @param TAG Your owning class's logging tag
|
||||
*/
|
||||
public void markAsDiscardedByNative(String TAG) {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
if (!usedByNativeCode) {
|
||||
Log.w(TAG,
|
||||
"This should not have happened: Discarding by native code, but not marked as used!");
|
||||
}
|
||||
usedByNativeCode = false;
|
||||
nativePointer = 0;
|
||||
usedByNativeCodeSync.notifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the native pointer value. Will be 0 if discarded by native code!.
|
||||
*
|
||||
* @return pointer (cast as a long)
|
||||
*/
|
||||
public long getNativePointer() {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
return nativePointer;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait until {@code markAsDiscardedByNative} has been called indicating that the native code is
|
||||
* done with this. Be sure to check the result!
|
||||
*
|
||||
* @param TAG Your owning class's logging tag
|
||||
* @return true if this class has successfully been discarded by native.
|
||||
*/
|
||||
@CheckResult
|
||||
public boolean blockUntilNativeDiscard(@NonNull String TAG) {
|
||||
try {
|
||||
synchronized (usedByNativeCodeSync) {
|
||||
while (usedByNativeCode) {
|
||||
usedByNativeCodeSync.wait();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
Log.i(TAG,
|
||||
"Interrupted while waiting for native code to finish up: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue