소스 검색

Deprecate and remove vendors specific XR APIs from the Godot core Android library

Follow-up to https://github.com/GodotVR/godot_openxr_vendors/pull/380, done in order to prevent vendors specific dependencies onto the Godot core Android library.
Fredia Huya-Kouadio 1 개월 전
부모
커밋
023024440b

+ 16 - 3
platform/android/java/lib/src/main/java/org/godotengine/godot/Godot.kt

@@ -1178,12 +1178,25 @@ class Godot private constructor(val context: Context) {
 	fun isProjectManagerHint() = isEditorBuild() && GodotLib.isProjectManagerHint()
 
 	/**
-	 * Return true if the given feature is supported.
+	 * Returns true if the feature for the given feature tag is supported in the currently running instance, depending
+	 * on the platform, build, etc.
+	 *
+	 * For reference, see https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-has-feature
+	 */
+	fun hasFeature(feature: String): Boolean {
+		return GodotLib.hasFeature(feature)
+	}
+
+	/**
+	 * Internal method used to query whether the host or the registered plugins supports a given feature.
+	 *
+	 * This is invoked by the native code, and should not be confused with [hasFeature] which is the Android version of
+	 * https://docs.godotengine.org/en/stable/classes/class_os.html#class-os-method-has-feature
 	 */
 	@Keep
-	private fun hasFeature(feature: String): Boolean {
+	private fun checkInternalFeatureSupport(feature: String): Boolean {
 		if (primaryHost?.supportsFeature(feature) == true) {
-			return true;
+			return true
 		}
 
 		for (plugin in pluginRegistry.allPlugins) {

+ 8 - 0
platform/android/java/lib/src/main/java/org/godotengine/godot/GodotGLRenderView.java

@@ -80,11 +80,13 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
 	private final GodotInputHandler inputHandler;
 	private final GodotRenderer godotRenderer;
 	private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
+	private final boolean isXrDevice;
 
 	public GodotGLRenderView(Godot godot, GodotInputHandler inputHandler, XRMode xrMode, boolean useDebugOpengl, boolean shouldBeTranslucent) {
 		super(godot.getContext());
 
 		this.godot = godot;
+		isXrDevice = godot.hasFeature("xr_runtime");
 		this.inputHandler = inputHandler;
 		this.godotRenderer = new GodotRenderer();
 		setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
@@ -172,6 +174,12 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView {
 		inputHandler.onPointerCaptureChange(hasCapture);
 	}
 
+	@Override
+	public boolean canCapturePointer() {
+		// Pointer capture is not supported on XR devices.
+		return !isXrDevice && inputHandler.canCapturePointer();
+	}
+
 	@Override
 	public void requestPointerCapture() {
 		if (canCapturePointer()) {

+ 2 - 0
platform/android/java/lib/src/main/java/org/godotengine/godot/GodotLib.java

@@ -314,4 +314,6 @@ public class GodotLib {
 	static native boolean isEditorHint();
 
 	static native boolean isProjectManagerHint();
+
+	static native boolean hasFeature(String feature);
 }

+ 1 - 5
platform/android/java/lib/src/main/java/org/godotengine/godot/GodotRenderView.java

@@ -31,7 +31,6 @@
 package org.godotengine.godot;
 
 import org.godotengine.godot.input.GodotInputHandler;
-import org.godotengine.godot.utils.DeviceUtils;
 
 import android.view.SurfaceView;
 
@@ -67,8 +66,5 @@ public interface GodotRenderView {
 	/**
 	 * @return true if pointer capture is supported.
 	 */
-	default boolean canCapturePointer() {
-		// Pointer capture is not supported on native XR devices.
-		return !DeviceUtils.isNativeXRDevice(getView().getContext()) && getInputHandler().canCapturePointer();
-	}
+	boolean canCapturePointer();
 }

+ 7 - 0
platform/android/java/lib/src/main/java/org/godotengine/godot/GodotVulkanRenderView.java

@@ -55,11 +55,13 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
 	private final GodotInputHandler mInputHandler;
 	private final VkRenderer mRenderer;
 	private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
+	private final boolean isXrDevice;
 
 	public GodotVulkanRenderView(Godot godot, GodotInputHandler inputHandler, boolean shouldBeTranslucent) {
 		super(godot.getContext());
 
 		this.godot = godot;
+		isXrDevice = godot.hasFeature("xr_runtime");
 		mInputHandler = inputHandler;
 		mRenderer = new VkRenderer();
 		setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
@@ -151,6 +153,11 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
 		return mInputHandler.onGenericMotionEvent(event);
 	}
 
+	@Override
+	public boolean canCapturePointer() {
+		// Pointer capture is not supported on XR devices.
+		return !isXrDevice && mInputHandler.canCapturePointer();
+	}
 	@Override
 	public void requestPointerCapture() {
 		if (canCapturePointer()) {

+ 0 - 60
platform/android/java/lib/src/main/java/org/godotengine/godot/utils/DeviceUtils.kt

@@ -1,60 +0,0 @@
-/**************************************************************************/
-/*  DeviceUtils.kt                                                        */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-/**
- * Contains utility methods for detecting specific devices.
- */
-@file:JvmName("DeviceUtils")
-
-package org.godotengine.godot.utils
-
-import android.content.Context
-import android.os.Build
-
-/**
- * Returns true if running on Meta Horizon OS.
- */
-fun isHorizonOSDevice(context: Context): Boolean {
-	return context.packageManager.hasSystemFeature("oculus.hardware.standalone_vr")
-}
-
-/**
- * Returns true if running on PICO OS.
- */
-fun isPicoOSDevice(): Boolean {
-	return ("Pico".equals(Build.BRAND, true))
-}
-
-/**
- * Returns true if running on a native Android XR device.
- */
-fun isNativeXRDevice(context: Context): Boolean {
-	return isHorizonOSDevice(context) || isPicoOSDevice()
-}

+ 3 - 2
platform/android/java/lib/src/main/java/org/godotengine/godot/utils/PermissionsUtil.java

@@ -30,6 +30,8 @@
 
 package org.godotengine.godot.utils;
 
+import org.godotengine.godot.Godot;
+
 import android.Manifest;
 import android.app.Activity;
 import android.content.Context;
@@ -50,7 +52,6 @@ import androidx.core.content.ContextCompat;
 
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -159,7 +160,7 @@ public final class PermissionsUtil {
 
 			case "CAMERA":
 				permissions.add(Manifest.permission.CAMERA);
-				if (DeviceUtils.isHorizonOSDevice(activity)) {
+				if (Godot.getInstance(activity).hasFeature("horizonos")) {
 					// On HorizonOS, these permissions are required to get access to all the device's cameras.
 					permissions.add("horizonos.permission.AVATAR_CAMERA");
 					permissions.add("horizonos.permission.HEADSET_CAMERA");

+ 0 - 79
platform/android/java/lib/src/main/java/org/godotengine/godot/xr/HybridAppUtils.kt

@@ -1,79 +0,0 @@
-/**************************************************************************/
-/*  HybridAppUtils.kt                                                     */
-/**************************************************************************/
-/*                         This file is part of:                          */
-/*                             GODOT ENGINE                               */
-/*                        https://godotengine.org                         */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */
-/*                                                                        */
-/* Permission is hereby granted, free of charge, to any person obtaining  */
-/* a copy of this software and associated documentation files (the        */
-/* "Software"), to deal in the Software without restriction, including    */
-/* without limitation the rights to use, copy, modify, merge, publish,    */
-/* distribute, sublicense, and/or sell copies of the Software, and to     */
-/* permit persons to whom the Software is furnished to do so, subject to  */
-/* the following conditions:                                              */
-/*                                                                        */
-/* The above copyright notice and this permission notice shall be         */
-/* included in all copies or substantial portions of the Software.        */
-/*                                                                        */
-/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */
-/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */
-/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
-/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */
-/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */
-/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */
-/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */
-/**************************************************************************/
-
-/**
- * Contains utility methods and constants for hybrid apps.
- */
-@file:JvmName("HybridAppUtils")
-
-package org.godotengine.godot.xr
-
-import android.util.Log
-import org.godotengine.godot.GodotLib
-
-private const val TAG = "HybridAppUtils"
-
-enum class HybridMode(private val nativeValue: Int) {
-	NONE( -1),
-	IMMERSIVE(0),
-	PANEL(1);
-
-	companion object {
-		fun fromNative(nativeValue: Int): HybridMode {
-			for (mode in HybridMode.entries) {
-				if (mode.nativeValue == nativeValue) {
-					return mode
-				}
-			}
-			return NONE
-		}
-	}
-}
-
-const val HYBRID_APP_FEATURE = "godot_openxr_hybrid_app"
-const val HYBRID_APP_PANEL_FEATURE = "godot_openxr_panel_app"
-const val HYBRID_APP_PANEL_CATEGORY = "org.godotengine.xr.hybrid.PANEL"
-const val HYBRID_APP_IMMERSIVE_CATEGORY = "org.godotengine.xr.hybrid.IMMERSIVE"
-
-fun isHybridAppEnabled() = GodotLib.getGlobal("xr/hybrid_app/enabled").toBoolean()
-
-fun getHybridAppLaunchMode(): HybridMode {
-	if (!isHybridAppEnabled()) {
-		return HybridMode.NONE
-	}
-
-	try {
-		val launchModeValue = GodotLib.getGlobal("xr/hybrid_app/launch_mode").toInt()
-		return HybridMode.fromNative(launchModeValue)
-	} catch (e: Exception) {
-		Log.w(TAG, "Unable to retrieve 'xr/hybrid_app/launch_mode' project setting", e)
-		return HybridMode.NONE
-	}
-}

+ 9 - 0
platform/android/java_godot_lib_jni.cpp

@@ -674,4 +674,13 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_isProjectManagerH
 	}
 	return false;
 }
+
+JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_hasFeature(JNIEnv *env, jclass clazz, jstring p_feature) {
+	OS *os = OS::get_singleton();
+	if (os) {
+		String feature = jstring_to_string(p_feature, env);
+		return os->has_feature(feature);
+	}
+	return false;
+}
 }

+ 1 - 0
platform/android/java_godot_lib_jni.h

@@ -77,4 +77,5 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_shouldDispatchInp
 JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getProjectResourceDir(JNIEnv *env, jclass clazz);
 JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_isEditorHint(JNIEnv *env, jclass clazz);
 JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_isProjectManagerHint(JNIEnv *env, jclass clazz);
+JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_hasFeature(JNIEnv *env, jclass clazz, jstring p_feature);
 }

+ 4 - 4
platform/android/java_godot_wrapper.cpp

@@ -80,7 +80,7 @@ GodotJavaWrapper::GodotJavaWrapper(JNIEnv *p_env, jobject p_godot_instance) {
 	_end_benchmark_measure = p_env->GetMethodID(godot_class, "nativeEndBenchmarkMeasure", "(Ljava/lang/String;Ljava/lang/String;)V");
 	_dump_benchmark = p_env->GetMethodID(godot_class, "nativeDumpBenchmark", "(Ljava/lang/String;)V");
 	_get_gdextension_list_config_file = p_env->GetMethodID(godot_class, "getGDExtensionConfigFiles", "()[Ljava/lang/String;");
-	_has_feature = p_env->GetMethodID(godot_class, "hasFeature", "(Ljava/lang/String;)Z");
+	_check_internal_feature_support = p_env->GetMethodID(godot_class, "checkInternalFeatureSupport", "(Ljava/lang/String;)Z");
 	_sign_apk = p_env->GetMethodID(godot_class, "nativeSignApk", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I");
 	_verify_apk = p_env->GetMethodID(godot_class, "nativeVerifyApk", "(Ljava/lang/String;)I");
 	_enable_immersive_mode = p_env->GetMethodID(godot_class, "nativeEnableImmersiveMode", "(Z)V");
@@ -517,13 +517,13 @@ void GodotJavaWrapper::dump_benchmark(const String &benchmark_file) {
 	}
 }
 
-bool GodotJavaWrapper::has_feature(const String &p_feature) const {
-	if (_has_feature) {
+bool GodotJavaWrapper::check_internal_feature_support(const String &p_feature) const {
+	if (_check_internal_feature_support) {
 		JNIEnv *env = get_jni_env();
 		ERR_FAIL_NULL_V(env, false);
 
 		jstring j_feature = env->NewStringUTF(p_feature.utf8().get_data());
-		bool result = env->CallBooleanMethod(godot_instance, _has_feature, j_feature);
+		bool result = env->CallBooleanMethod(godot_instance, _check_internal_feature_support, j_feature);
 		env->DeleteLocalRef(j_feature);
 		return result;
 	} else {

+ 2 - 2
platform/android/java_godot_wrapper.h

@@ -76,7 +76,7 @@ private:
 	jmethodID _begin_benchmark_measure = nullptr;
 	jmethodID _end_benchmark_measure = nullptr;
 	jmethodID _dump_benchmark = nullptr;
-	jmethodID _has_feature = nullptr;
+	jmethodID _check_internal_feature_support = nullptr;
 	jmethodID _sign_apk = nullptr;
 	jmethodID _verify_apk = nullptr;
 	jmethodID _enable_immersive_mode = nullptr;
@@ -129,7 +129,7 @@ public:
 	Vector<String> get_gdextension_list_config_file() const;
 
 	// Return true if the given feature is supported.
-	bool has_feature(const String &p_feature) const;
+	bool check_internal_feature_support(const String &p_feature) const;
 
 	// Sign and verify apks
 	Error sign_apk(const String &p_input_path, const String &p_output_path, const String &p_keystore_path, const String &p_keystore_user, const String &p_keystore_password);

+ 1 - 1
platform/android/os_android.cpp

@@ -878,7 +878,7 @@ bool OS_Android::_check_internal_feature_support(const String &p_feature) {
 	}
 #endif
 
-	if (godot_java->has_feature(p_feature)) {
+	if (godot_java->check_internal_feature_support(p_feature)) {
 		return true;
 	}