Selaa lähdekoodia

Merge pull request #101645 from m4gr3d/disable_xr_mode_for_regular_launch

Clean up the XR editor logic
Thaddeus Crews 6 kuukautta sitten
vanhempi
commit
041cb204c3

+ 7 - 0
platform/android/export/export_plugin.cpp

@@ -2840,6 +2840,13 @@ void EditorExportPlatformAndroid::get_command_line_flags(const Ref<EditorExportP
 		command_line_strings.push_back("--xr_mode_openxr");
 	} else { // XRMode.REGULAR is the default.
 		command_line_strings.push_back("--xr_mode_regular");
+
+		// Also override the 'xr/openxr/enabled' project setting.
+		// This is useful for multi-platforms projects supporting both XR and non-XR devices. The project would need
+		// to enable openxr for development, and would create multiple XR and non-XR export presets.
+		// These command line args ensure that the non-XR export presets will have openxr disabled.
+		command_line_strings.push_back("--xr-mode");
+		command_line_strings.push_back("off");
 	}
 
 	bool immersive = p_preset->get("screen/immersive_mode");

+ 1 - 2
platform/android/java/editor/src/android/java/org/godotengine/editor/GodotEditor.kt

@@ -35,5 +35,4 @@ package org.godotengine.editor
  *
  * This is the implementation of the editor used when running on regular Android devices.
  */
-open class GodotEditor : BaseGodotEditor() {
-}
+open class GodotEditor : BaseGodotEditor()

+ 1 - 8
platform/android/java/editor/src/horizonos/AndroidManifest.xml

@@ -57,15 +57,8 @@
 
         <activity
             android:name=".GodotXRGame"
-            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
-            android:process=":GodotXRGame"
-            android:launchMode="singleTask"
-            android:icon="@mipmap/ic_play_window"
-            android:label="@string/godot_game_activity_name"
             android:exported="false"
-            android:screenOrientation="landscape"
-            android:resizeableActivity="false"
-            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+            tools:node="merge">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />

+ 5 - 64
platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotEditor.kt

@@ -30,9 +30,6 @@
 
 package org.godotengine.editor
 
-import org.godotengine.godot.GodotLib
-import org.godotengine.godot.utils.isNativeXRDevice
-
 /**
  * Primary window of the Godot Editor.
  *
@@ -40,66 +37,10 @@ import org.godotengine.godot.utils.isNativeXRDevice
  */
 open class GodotEditor : BaseGodotEditor() {
 
-	companion object {
-		private val TAG = GodotEditor::class.java.simpleName
-
-		/** Default behavior, means we check project settings **/
-		private const val XR_MODE_DEFAULT = "default"
-
-		/**
-		 * Ignore project settings, OpenXR is disabled
-		 */
-		private const val XR_MODE_OFF = "off"
-
-		/**
-		 * Ignore project settings, OpenXR is enabled
-		 */
-		private const val XR_MODE_ON = "on"
-
-		internal val XR_RUN_GAME_INFO = EditorWindowInfo(GodotXRGame::class.java, 1667, ":GodotXRGame")
-
-		internal val USE_SCENE_PERMISSIONS = listOf("com.oculus.permission.USE_SCENE", "horizonos.permission.USE_SCENE")
-	}
-
-	override fun getExcludedPermissions(): MutableSet<String> {
-		val excludedPermissions = super.getExcludedPermissions()
-		// The USE_SCENE permission is requested when the "xr/openxr/enabled" project setting
-		// is enabled.
-		excludedPermissions.addAll(USE_SCENE_PERMISSIONS)
-		return excludedPermissions
-	}
-
-	override fun retrieveEditorWindowInfo(args: Array<String>): EditorWindowInfo {
-		var hasEditor = false
-		var xrMode = XR_MODE_DEFAULT
-
-		var i = 0
-		while (i < args.size) {
-			when (args[i++]) {
-				EDITOR_ARG, EDITOR_ARG_SHORT, EDITOR_PROJECT_MANAGER_ARG, EDITOR_PROJECT_MANAGER_ARG_SHORT -> hasEditor = true
-				XR_MODE_ARG -> {
-					xrMode = args[i++]
-				}
-			}
-		}
-
-		return if (hasEditor) {
-			EDITOR_MAIN_INFO
-		} else {
-			val openxrEnabled = xrMode == XR_MODE_ON ||
-				(xrMode == XR_MODE_DEFAULT && GodotLib.getGlobal("xr/openxr/enabled").toBoolean())
-			if (openxrEnabled && isNativeXRDevice()) {
-				XR_RUN_GAME_INFO
-			} else {
-				RUN_GAME_INFO
-			}
-		}
-	}
-
-	override fun getEditorWindowInfoForInstanceId(instanceId: Int): EditorWindowInfo? {
-		return when (instanceId) {
-			XR_RUN_GAME_INFO.windowId -> XR_RUN_GAME_INFO
-			else -> super.getEditorWindowInfoForInstanceId(instanceId)
-		}
+	override fun getXRRuntimePermissions(): MutableSet<String> {
+		val xrRuntimePermissions = super.getXRRuntimePermissions()
+		xrRuntimePermissions.add("com.oculus.permission.USE_SCENE")
+		xrRuntimePermissions.add("horizonos.permission.USE_SCENE")
+		return xrRuntimePermissions
 	}
 }

+ 12 - 0
platform/android/java/editor/src/main/AndroidManifest.xml

@@ -71,6 +71,18 @@
                 android:defaultWidth="@dimen/editor_default_window_width"
                 android:defaultHeight="@dimen/editor_default_window_height" />
         </activity>
+        <activity
+            android:name=".GodotXRGame"
+            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
+            android:process=":GodotXRGame"
+            android:launchMode="singleTask"
+            android:icon="@mipmap/ic_play_window"
+            android:label="@string/godot_game_activity_name"
+            android:exported="false"
+            android:screenOrientation="landscape"
+            android:resizeableActivity="false"
+            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+        </activity>
     </application>
 
 </manifest>

+ 47 - 18
platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt

@@ -47,13 +47,12 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
 import androidx.window.layout.WindowMetricsCalculator
 import org.godotengine.editor.utils.signApk
 import org.godotengine.editor.utils.verifyApk
+import org.godotengine.godot.BuildConfig
 import org.godotengine.godot.GodotActivity
 import org.godotengine.godot.GodotLib
 import org.godotengine.godot.error.Error
 import org.godotengine.godot.utils.PermissionsUtil
 import org.godotengine.godot.utils.ProcessPhoenix
-import org.godotengine.godot.utils.isHorizonOSDevice
-import org.godotengine.godot.utils.isPicoOSDevice
 import org.godotengine.godot.utils.isNativeXRDevice
 import java.util.*
 import kotlin.math.min
@@ -93,6 +92,20 @@ abstract class BaseGodotEditor : GodotActivity() {
 		// Info for the various classes used by the editor
 		internal val EDITOR_MAIN_INFO = EditorWindowInfo(GodotEditor::class.java, 777, "")
 		internal val RUN_GAME_INFO = EditorWindowInfo(GodotGame::class.java, 667, ":GodotGame", LaunchPolicy.AUTO, true)
+		internal val XR_RUN_GAME_INFO = EditorWindowInfo(GodotXRGame::class.java, 1667, ":GodotXRGame")
+
+		/** Default behavior, means we check project settings **/
+		private const val XR_MODE_DEFAULT = "default"
+
+		/**
+		 * Ignore project settings, OpenXR is disabled
+		 */
+		private const val XR_MODE_OFF = "off"
+
+		/**
+		 * Ignore project settings, OpenXR is enabled
+		 */
+		private const val XR_MODE_ON = "on"
 
 		/**
 		 * Sets of constants to specify the window to use to run the project.
@@ -129,8 +142,7 @@ abstract class BaseGodotEditor : GodotActivity() {
 	 *
 	 * The permissions in this set will be requested on demand based on use cases.
 	 */
-	@CallSuper
-	protected open fun getExcludedPermissions(): MutableSet<String> {
+	private fun getExcludedPermissions(): MutableSet<String> {
 		val excludedPermissions = mutableSetOf(
 			// The RECORD_AUDIO permission is requested when the "audio/driver/enable_input" project
 			// setting is enabled.
@@ -144,9 +156,21 @@ abstract class BaseGodotEditor : GodotActivity() {
 				Manifest.permission.REQUEST_INSTALL_PACKAGES,
 			)
 		}
+
+		// XR runtime permissions should only be requested when the "xr/openxr/enabled" project setting
+		// is enabled.
+		excludedPermissions.addAll(getXRRuntimePermissions())
 		return excludedPermissions
 	}
 
+	/**
+	 * Set of permissions to request when the "xr/openxr/enabled" project setting is enabled.
+	 */
+	@CallSuper
+	protected open fun getXRRuntimePermissions(): MutableSet<String> {
+		return mutableSetOf()
+	}
+
 	override fun onCreate(savedInstanceState: Bundle?) {
 		installSplashScreen()
 
@@ -208,27 +232,38 @@ abstract class BaseGodotEditor : GodotActivity() {
 
 	final override fun getCommandLine() = commandLineParams
 
-	protected open fun retrieveEditorWindowInfo(args: Array<String>): EditorWindowInfo {
+	protected fun retrieveEditorWindowInfo(args: Array<String>): EditorWindowInfo {
 		var hasEditor = false
+		var xrMode = XR_MODE_DEFAULT
 
 		var i = 0
 		while (i < args.size) {
 			when (args[i++]) {
 				EDITOR_ARG, EDITOR_ARG_SHORT, EDITOR_PROJECT_MANAGER_ARG, EDITOR_PROJECT_MANAGER_ARG_SHORT -> hasEditor = true
+				XR_MODE_ARG -> {
+					xrMode = args[i++]
+				}
 			}
 		}
 
 		return if (hasEditor) {
 			EDITOR_MAIN_INFO
 		} else {
-			RUN_GAME_INFO
+			val openxrEnabled = xrMode == XR_MODE_ON ||
+				(xrMode == XR_MODE_DEFAULT && GodotLib.getGlobal("xr/openxr/enabled").toBoolean())
+			if (openxrEnabled && isNativeXRDevice(applicationContext)) {
+				XR_RUN_GAME_INFO
+			} else {
+				RUN_GAME_INFO
+			}
 		}
 	}
 
-	protected open fun getEditorWindowInfoForInstanceId(instanceId: Int): EditorWindowInfo? {
+	private fun getEditorWindowInfoForInstanceId(instanceId: Int): EditorWindowInfo? {
 		return when (instanceId) {
 			RUN_GAME_INFO.windowId -> RUN_GAME_INFO
 			EDITOR_MAIN_INFO.windowId -> EDITOR_MAIN_INFO
+			XR_RUN_GAME_INFO.windowId -> XR_RUN_GAME_INFO
 			else -> null
 		}
 	}
@@ -417,8 +452,8 @@ abstract class BaseGodotEditor : GodotActivity() {
 
 		return when (policy) {
 			LaunchPolicy.AUTO -> {
-				if (isHorizonOSDevice()) {
-					// Horizon OS UX is more desktop-like and has support for launching adjacent
+				if (isNativeXRDevice(applicationContext)) {
+					// Native XR devices are more desktop-like and have support for launching adjacent
 					// windows. So we always want to launch in adjacent mode when auto is selected.
 					LaunchPolicy.ADJACENT
 				} else {
@@ -450,12 +485,6 @@ abstract class BaseGodotEditor : GodotActivity() {
 	 * Returns true the if the device supports picture-in-picture (PiP)
 	 */
 	protected open fun hasPiPSystemFeature(): Boolean {
-		if (isNativeXRDevice()) {
-			// Known native XR devices do not support PiP.
-			// Will need to revisit as they update their OS.
-			return false
-		}
-
 		return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
 			packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
 	}
@@ -534,15 +563,15 @@ abstract class BaseGodotEditor : GodotActivity() {
 
 	override fun supportsFeature(featureTag: String): Boolean {
 		if (featureTag == "xr_editor") {
-			return isNativeXRDevice()
+			return isNativeXRDevice(applicationContext)
 		}
 
 		if (featureTag == "horizonos") {
-			return isHorizonOSDevice()
+			return BuildConfig.FLAVOR == "horizonos"
 		}
 
 		if (featureTag == "picoos") {
-			return isPicoOSDevice()
+			return BuildConfig.FLAVOR == "picoos"
 		}
 
         return false

+ 3 - 3
platform/android/java/editor/src/horizonos/java/org/godotengine/editor/GodotXRGame.kt → platform/android/java/editor/src/main/java/org/godotengine/editor/GodotXRGame.kt

@@ -59,8 +59,8 @@ open class GodotXRGame: GodotGame() {
 	override fun getProjectPermissionsToEnable(): MutableList<String> {
 		val permissionsToEnable = super.getProjectPermissionsToEnable()
 
-		val openxrEnabled = GodotLib.getGlobal("xr/openxr/enabled").toBoolean()
-		if (openxrEnabled) {
+		val xrRuntimePermission = getXRRuntimePermissions()
+		if (xrRuntimePermission.isNotEmpty() && GodotLib.getGlobal("xr/openxr/enabled").toBoolean()) {
 			// We only request permissions when the `automatically_request_runtime_permissions`
 			// project setting is enabled.
 			// If the project setting is not defined, we fall-back to the default behavior which is
@@ -69,7 +69,7 @@ open class GodotXRGame: GodotGame() {
 			val automaticPermissionsRequestEnabled = automaticallyRequestPermissionsSetting.isNullOrEmpty() ||
 				automaticallyRequestPermissionsSetting.toBoolean()
 			if (automaticPermissionsRequestEnabled) {
-				permissionsToEnable.addAll(USE_SCENE_PERMISSIONS)
+				permissionsToEnable.addAll(xrRuntimePermission)
 			}
 		}
 

+ 1 - 1
platform/android/java/editor/src/main/res/values/dimens.xml

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
-	<dimen name="editor_default_window_height">640dp</dimen>
+	<dimen name="editor_default_window_height">720dp</dimen>
 	<dimen name="editor_default_window_width">1024dp</dimen>
 </resources>

+ 1 - 8
platform/android/java/editor/src/picoos/AndroidManifest.xml

@@ -29,15 +29,8 @@
 
         <activity
             android:name=".GodotXRGame"
-            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
-            android:process=":GodotXRGame"
-            android:launchMode="singleTask"
-            android:icon="@mipmap/ic_play_window"
-            android:label="@string/godot_game_activity_name"
             android:exported="false"
-            android:screenOrientation="landscape"
-            android:resizeableActivity="false"
-            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen">
+            tools:node="merge">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.DEFAULT" />

+ 1 - 45
platform/android/java/editor/src/picoos/java/org/godotengine/editor/GodotEditor.kt

@@ -30,53 +30,9 @@
 
 package org.godotengine.editor
 
-import org.godotengine.godot.GodotLib
-import org.godotengine.godot.utils.isNativeXRDevice
-
 /**
  * Primary window of the Godot Editor.
  *
  * This is the implementation of the editor used when running on PicoOS devices.
  */
-open class GodotEditor : BaseGodotEditor() {
-
-	companion object {
-		private val TAG = GodotEditor::class.java.simpleName
-
-		internal val XR_RUN_GAME_INFO = EditorWindowInfo(GodotXRGame::class.java, 1667, ":GodotXRGame")
-	}
-
-	override fun retrieveEditorWindowInfo(args: Array<String>): EditorWindowInfo {
-		var hasEditor = false
-		var xrModeOn = false
-
-		var i = 0
-		while (i < args.size) {
-			when (args[i++]) {
-				EDITOR_ARG, EDITOR_ARG_SHORT, EDITOR_PROJECT_MANAGER_ARG, EDITOR_PROJECT_MANAGER_ARG_SHORT -> hasEditor = true
-				XR_MODE_ARG -> {
-					val argValue = args[i++]
-					xrModeOn = xrModeOn || ("on" == argValue)
-				}
-			}
-		}
-
-		return if (hasEditor) {
-			EDITOR_MAIN_INFO
-		} else {
-			val openxrEnabled = GodotLib.getGlobal("xr/openxr/enabled").toBoolean()
-			if (openxrEnabled && isNativeXRDevice()) {
-				XR_RUN_GAME_INFO
-			} else {
-				RUN_GAME_INFO
-			}
-		}
-	}
-
-	override fun getEditorWindowInfoForInstanceId(instanceId: Int): EditorWindowInfo? {
-		return when (instanceId) {
-			XR_RUN_GAME_INFO.windowId -> XR_RUN_GAME_INFO
-			else -> super.getEditorWindowInfoForInstanceId(instanceId)
-		}
-	}
-}
+open class GodotEditor : BaseGodotEditor()

+ 0 - 59
platform/android/java/editor/src/picoos/java/org/godotengine/editor/GodotXRGame.kt

@@ -1,59 +0,0 @@
-/*************************************************************************/
-/*  GodotXRGame.kt                                                       */
-/*************************************************************************/
-/*                       This file is part of:                           */
-/*                           GODOT ENGINE                                */
-/*                      https://godotengine.org                          */
-/*************************************************************************/
-/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.                 */
-/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).   */
-/*                                                                       */
-/* 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.                */
-/*************************************************************************/
-
-package org.godotengine.editor
-
-import org.godotengine.godot.GodotLib
-import org.godotengine.godot.xr.XRMode
-
-/**
- * Provide support for running XR apps / games from the editor window.
- */
-open class GodotXRGame: GodotGame() {
-
-	override fun overrideOrientationRequest() = true
-
-	override fun updateCommandLineParams(args: List<String>) {
-		val updatedArgs = ArrayList<String>()
-		if (!args.contains(XRMode.OPENXR.cmdLineArg)) {
-			updatedArgs.add(XRMode.OPENXR.cmdLineArg)
-		}
-		if (!args.contains(XR_MODE_ARG)) {
-			updatedArgs.add(XR_MODE_ARG)
-			updatedArgs.add("on")
-		}
-		updatedArgs.addAll(args)
-
-		super.updateCommandLineParams(updatedArgs)
-	}
-
-	override fun getEditorWindowInfo() = XR_RUN_GAME_INFO
-
-}

+ 2 - 2
platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java

@@ -68,7 +68,7 @@ public interface GodotRenderView {
 	 * @return true if pointer capture is supported.
 	 */
 	default boolean canCapturePointer() {
-		// Pointer capture is not supported on Horizon OS
-		return !DeviceUtils.isHorizonOSDevice() && getInputHandler().canCapturePointer();
+		// Pointer capture is not supported on native XR devices.
+		return !DeviceUtils.isNativeXRDevice(getView().getContext()) && getInputHandler().canCapturePointer();
 	}
 }

+ 5 - 4
platform/android/java/lib/src/org/godotengine/godot/utils/DeviceUtils.kt

@@ -35,13 +35,14 @@
 
 package org.godotengine.godot.utils
 
+import android.content.Context
 import android.os.Build
 
 /**
  * Returns true if running on Meta Horizon OS.
  */
-fun isHorizonOSDevice(): Boolean {
-	return "Oculus".equals(Build.BRAND, true)
+fun isHorizonOSDevice(context: Context): Boolean {
+	return context.packageManager.hasSystemFeature("oculus.hardware.standalone_vr")
 }
 
 /**
@@ -54,6 +55,6 @@ fun isPicoOSDevice(): Boolean {
 /**
  * Returns true if running on a native Android XR device.
  */
-fun isNativeXRDevice(): Boolean {
-	return isHorizonOSDevice() || isPicoOSDevice()
+fun isNativeXRDevice(context: Context): Boolean {
+	return isHorizonOSDevice(context) || isPicoOSDevice()
 }