Merge pull request #96624 from m4gr3d/android_editor_improvements
[Android editor] Improve support for XR projects
This commit is contained in:
commit
0e9950bde1
22 changed files with 572 additions and 99 deletions
1
.github/workflows/android_builds.yml
vendored
1
.github/workflows/android_builds.yml
vendored
|
@ -85,6 +85,7 @@ jobs:
|
|||
run: |
|
||||
cd platform/android/java
|
||||
./gradlew generateGodotEditor
|
||||
./gradlew generateGodotMetaEditor
|
||||
cd ../../..
|
||||
ls -l bin/android_editor_builds/
|
||||
|
||||
|
|
|
@ -1037,7 +1037,8 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
|
|||
if (arg == "--audio-driver" ||
|
||||
arg == "--display-driver" ||
|
||||
arg == "--rendering-method" ||
|
||||
arg == "--rendering-driver") {
|
||||
arg == "--rendering-driver" ||
|
||||
arg == "--xr-mode") {
|
||||
if (N) {
|
||||
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(arg);
|
||||
forwardable_cli_arguments[CLI_SCOPE_TOOL].push_back(N->get());
|
||||
|
|
|
@ -271,17 +271,14 @@ OpenXRAPI *OpenXRAPI::singleton = nullptr;
|
|||
Vector<OpenXRExtensionWrapper *> OpenXRAPI::registered_extension_wrappers;
|
||||
|
||||
bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
|
||||
// @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
|
||||
|
||||
if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
|
||||
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
|
||||
return false;
|
||||
} else {
|
||||
if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
|
||||
return GLOBAL_GET("xr/openxr/enabled");
|
||||
if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) {
|
||||
if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
|
||||
return GLOBAL_GET("xr/openxr/enabled.editor");
|
||||
} else {
|
||||
return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
|
||||
return GLOBAL_GET("xr/openxr/enabled");
|
||||
}
|
||||
} else {
|
||||
return XRServer::get_xr_mode() == XRServer::XRMODE_ON;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -557,14 +554,11 @@ bool OpenXRAPI::create_instance() {
|
|||
extension_ptrs.push_back(enabled_extensions[i].get_data());
|
||||
}
|
||||
|
||||
// Get our project name
|
||||
String project_name = GLOBAL_GET("application/config/name");
|
||||
|
||||
// Create our OpenXR instance
|
||||
XrApplicationInfo application_info{
|
||||
"", // applicationName, we'll set this down below
|
||||
"Godot Engine", // applicationName, if we're running a game we'll update this down below.
|
||||
1, // applicationVersion, we don't currently have this
|
||||
"Godot Game Engine", // engineName
|
||||
"Godot Engine", // engineName
|
||||
VERSION_MAJOR * 10000 + VERSION_MINOR * 100 + VERSION_PATCH, // engineVersion 4.0 -> 40000, 4.0.1 -> 40001, 4.1 -> 40100, etc.
|
||||
XR_API_VERSION_1_0 // apiVersion
|
||||
};
|
||||
|
@ -588,7 +582,11 @@ bool OpenXRAPI::create_instance() {
|
|||
extension_ptrs.ptr() // enabledExtensionNames
|
||||
};
|
||||
|
||||
copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
|
||||
// Get our project name
|
||||
String project_name = GLOBAL_GET("application/config/name");
|
||||
if (!project_name.is_empty()) {
|
||||
copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
|
||||
}
|
||||
|
||||
XrResult result = xrCreateInstance(&instance_create_info, &instance);
|
||||
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "Failed to create XR instance.");
|
||||
|
@ -2583,7 +2581,6 @@ OpenXRAPI::OpenXRAPI() {
|
|||
|
||||
if (Engine::get_singleton()->is_editor_hint()) {
|
||||
// Enabled OpenXR in the editor? Adjust our settings for the editor
|
||||
|
||||
} else {
|
||||
// Load settings from project settings
|
||||
int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor");
|
||||
|
|
|
@ -12,6 +12,7 @@ allprojects {
|
|||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}
|
||||
|
||||
// Godot user plugins custom maven repos
|
||||
String[] mavenRepos = getGodotPluginsMavenRepos()
|
||||
|
|
|
@ -11,6 +11,7 @@ pluginManagement {
|
|||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,12 +18,14 @@ allprojects {
|
|||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}
|
||||
}
|
||||
}
|
||||
|
||||
ext {
|
||||
supportedAbis = ["arm32", "arm64", "x86_32", "x86_64"]
|
||||
supportedFlavors = ["editor", "template"]
|
||||
supportedEditorVendors = ["google", "meta"]
|
||||
supportedFlavorsBuildTypes = [
|
||||
"editor": ["dev", "debug", "release"],
|
||||
"template": ["dev", "debug", "release"]
|
||||
|
@ -92,15 +94,20 @@ def templateExcludedBuildTask() {
|
|||
/**
|
||||
* Generates the build tasks for the given flavor
|
||||
* @param flavor Must be one of the supported flavors ('template' / 'editor')
|
||||
* @param editorVendor Must be one of the supported editor vendors ('google' / 'meta')
|
||||
*/
|
||||
def generateBuildTasks(String flavor = "template") {
|
||||
def generateBuildTasks(String flavor = "template", String editorVendor = "google") {
|
||||
if (!supportedFlavors.contains(flavor)) {
|
||||
throw new GradleException("Invalid build flavor: $flavor")
|
||||
}
|
||||
if (!supportedEditorVendors.contains(editorVendor)) {
|
||||
throw new GradleException("Invalid editor vendor: $editorVendor")
|
||||
}
|
||||
|
||||
String capitalizedEditorVendor = editorVendor.capitalize()
|
||||
def buildTasks = []
|
||||
|
||||
// Only build the apks and aar files for which we have native shared libraries unless we intend
|
||||
// Only build the binary files for which we have native shared libraries unless we intend
|
||||
// to run the scons build tasks.
|
||||
boolean excludeSconsBuildTasks = excludeSconsBuildTasks()
|
||||
boolean isTemplate = flavor == "template"
|
||||
|
@ -163,28 +170,28 @@ def generateBuildTasks(String flavor = "template") {
|
|||
}
|
||||
} else {
|
||||
// Copy the generated editor apk to the bin directory.
|
||||
String copyEditorApkTaskName = "copyEditor${capitalizedTarget}ApkToBin"
|
||||
String copyEditorApkTaskName = "copyEditor${capitalizedEditorVendor}${capitalizedTarget}ApkToBin"
|
||||
if (tasks.findByName(copyEditorApkTaskName) != null) {
|
||||
buildTasks += tasks.getByName(copyEditorApkTaskName)
|
||||
} else {
|
||||
buildTasks += tasks.create(name: copyEditorApkTaskName, type: Copy) {
|
||||
dependsOn ":editor:assemble${capitalizedTarget}"
|
||||
from("editor/build/outputs/apk/${target}")
|
||||
dependsOn ":editor:assemble${capitalizedEditorVendor}${capitalizedTarget}"
|
||||
from("editor/build/outputs/apk/${editorVendor}/${target}")
|
||||
into(androidEditorBuildsDir)
|
||||
include("android_editor-${target}*.apk")
|
||||
include("android_editor-${editorVendor}-${target}*.apk")
|
||||
}
|
||||
}
|
||||
|
||||
// Copy the generated editor aab to the bin directory.
|
||||
String copyEditorAabTaskName = "copyEditor${capitalizedTarget}AabToBin"
|
||||
String copyEditorAabTaskName = "copyEditor${capitalizedEditorVendor}${capitalizedTarget}AabToBin"
|
||||
if (tasks.findByName(copyEditorAabTaskName) != null) {
|
||||
buildTasks += tasks.getByName(copyEditorAabTaskName)
|
||||
} else {
|
||||
buildTasks += tasks.create(name: copyEditorAabTaskName, type: Copy) {
|
||||
dependsOn ":editor:bundle${capitalizedTarget}"
|
||||
from("editor/build/outputs/bundle/${target}")
|
||||
dependsOn ":editor:bundle${capitalizedEditorVendor}${capitalizedTarget}"
|
||||
from("editor/build/outputs/bundle/${editorVendor}${capitalizedTarget}")
|
||||
into(androidEditorBuildsDir)
|
||||
include("android_editor-${target}*.aab")
|
||||
include("android_editor-${editorVendor}-${target}*.aab")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -197,15 +204,27 @@ def generateBuildTasks(String flavor = "template") {
|
|||
}
|
||||
|
||||
/**
|
||||
* Generate the Godot Editor Android apk.
|
||||
* Generate the Godot Editor Android binaries.
|
||||
*
|
||||
* Note: Unless the 'generateNativeLibs` argument is specified, the Godot 'tools' shared libraries
|
||||
* must have been generated (via scons) prior to running this gradle task.
|
||||
* The task will only build the apk(s) for which the shared libraries is available.
|
||||
* The task will only build the binaries for which the shared libraries is available.
|
||||
*/
|
||||
task generateGodotEditor {
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
dependsOn = generateBuildTasks("editor")
|
||||
dependsOn = generateBuildTasks("editor", "google")
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the Godot Editor Android binaries for Meta devices.
|
||||
*
|
||||
* Note: Unless the 'generateNativeLibs` argument is specified, the Godot 'tools' shared libraries
|
||||
* must have been generated (via scons) prior to running this gradle task.
|
||||
* The task will only build the binaries for which the shared libraries is available.
|
||||
*/
|
||||
task generateGodotMetaEditor {
|
||||
gradle.startParameter.excludedTaskNames += templateExcludedBuildTask()
|
||||
dependsOn = generateBuildTasks("editor", "meta")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,16 +5,6 @@ plugins {
|
|||
id 'base'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||
implementation project(":lib")
|
||||
|
||||
implementation "androidx.window:window:1.3.0"
|
||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
implementation "org.bouncycastle:bcprov-jdk15to18:1.77"
|
||||
}
|
||||
|
||||
ext {
|
||||
// Retrieve the build number from the environment variable; default to 0 if none is specified.
|
||||
// The build number is added as a suffix to the version code for upload to the Google Play store.
|
||||
|
@ -154,4 +144,37 @@ android {
|
|||
doNotStrip '**/*.so'
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions = ["vendor"]
|
||||
productFlavors {
|
||||
google {
|
||||
dimension "vendor"
|
||||
missingDimensionStrategy 'products', 'editor'
|
||||
}
|
||||
meta {
|
||||
dimension "vendor"
|
||||
missingDimensionStrategy 'products', 'editor'
|
||||
ndk {
|
||||
//noinspection ChromeOsAbiSupport
|
||||
abiFilters "arm64-v8a"
|
||||
}
|
||||
applicationIdSuffix ".meta"
|
||||
versionNameSuffix "-meta"
|
||||
minSdkVersion 23
|
||||
targetSdkVersion 32
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||
implementation project(":lib")
|
||||
|
||||
implementation "androidx.window:window:1.3.0"
|
||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||
implementation "org.bouncycastle:bcprov-jdk15to18:1.77"
|
||||
|
||||
// Meta dependencies
|
||||
metaImplementation "org.godotengine:godot-openxr-vendors-meta:3.0.0-stable"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/**************************************************************************/
|
||||
/* GodotEditor.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
package org.godotengine.editor
|
||||
|
||||
/**
|
||||
* Primary window of the Godot Editor.
|
||||
*
|
||||
* This is the implementation of the editor used when running on regular Android devices.
|
||||
*/
|
||||
open class GodotEditor : BaseGodotEditor() {
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/**************************************************************************/
|
||||
/* GodotEditor.kt */
|
||||
/* BaseGodotEditor.kt */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
|
@ -52,6 +52,8 @@ 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.isNativeXRDevice
|
||||
import java.util.*
|
||||
import kotlin.math.min
|
||||
|
||||
|
@ -61,13 +63,11 @@ import kotlin.math.min
|
|||
* This provides the basic templates for the activities making up this application.
|
||||
* Each derived activity runs in its own process, which enable up to have several instances of
|
||||
* the Godot engine up and running at the same time.
|
||||
*
|
||||
* It also plays the role of the primary editor window.
|
||||
*/
|
||||
open class GodotEditor : GodotActivity() {
|
||||
abstract class BaseGodotEditor : GodotActivity() {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotEditor::class.java.simpleName
|
||||
private val TAG = BaseGodotEditor::class.java.simpleName
|
||||
|
||||
private const val WAIT_FOR_DEBUGGER = false
|
||||
|
||||
|
@ -81,12 +81,13 @@ open class GodotEditor : GodotActivity() {
|
|||
// Command line arguments
|
||||
private const val FULLSCREEN_ARG = "--fullscreen"
|
||||
private const val FULLSCREEN_ARG_SHORT = "-f"
|
||||
private const val EDITOR_ARG = "--editor"
|
||||
private const val EDITOR_ARG_SHORT = "-e"
|
||||
private const val EDITOR_PROJECT_MANAGER_ARG = "--project-manager"
|
||||
private const val EDITOR_PROJECT_MANAGER_ARG_SHORT = "-p"
|
||||
private const val BREAKPOINTS_ARG = "--breakpoints"
|
||||
private const val BREAKPOINTS_ARG_SHORT = "-b"
|
||||
internal const val EDITOR_ARG = "--editor"
|
||||
internal const val EDITOR_ARG_SHORT = "-e"
|
||||
internal const val EDITOR_PROJECT_MANAGER_ARG = "--project-manager"
|
||||
internal const val EDITOR_PROJECT_MANAGER_ARG_SHORT = "-p"
|
||||
internal const val BREAKPOINTS_ARG = "--breakpoints"
|
||||
internal const val BREAKPOINTS_ARG_SHORT = "-b"
|
||||
internal const val XR_MODE_ARG = "--xr-mode"
|
||||
|
||||
// Info for the various classes used by the editor
|
||||
internal val EDITOR_MAIN_INFO = EditorWindowInfo(GodotEditor::class.java, 777, "")
|
||||
|
@ -122,6 +123,20 @@ open class GodotEditor : GodotActivity() {
|
|||
|
||||
internal open fun getEditorWindowInfo() = EDITOR_MAIN_INFO
|
||||
|
||||
/**
|
||||
* Set of permissions to be excluded when requesting all permissions at startup.
|
||||
*
|
||||
* The permissions in this set will be requested on demand based on use cases.
|
||||
*/
|
||||
@CallSuper
|
||||
protected open fun getExcludedPermissions(): MutableSet<String> {
|
||||
return mutableSetOf(
|
||||
// The RECORD_AUDIO permission is requested when the "audio/driver/enable_input" project
|
||||
// setting is enabled.
|
||||
Manifest.permission.RECORD_AUDIO
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
installSplashScreen()
|
||||
|
||||
|
@ -131,8 +146,8 @@ open class GodotEditor : GodotActivity() {
|
|||
}
|
||||
|
||||
// We exclude certain permissions from the set we request at startup, as they'll be
|
||||
// requested on demand based on use-cases.
|
||||
PermissionsUtil.requestManifestPermissions(this, setOf(Manifest.permission.RECORD_AUDIO))
|
||||
// requested on demand based on use cases.
|
||||
PermissionsUtil.requestManifestPermissions(this, getExcludedPermissions())
|
||||
|
||||
val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
Log.d(TAG, "Starting intent $intent with parameters ${params.contentToString()}")
|
||||
|
@ -152,8 +167,6 @@ open class GodotEditor : GodotActivity() {
|
|||
val longPressEnabled = enableLongPressGestures()
|
||||
val panScaleEnabled = enablePanAndScaleGestures()
|
||||
|
||||
checkForProjectPermissionsToEnable()
|
||||
|
||||
runOnUiThread {
|
||||
// Enable long press, panning and scaling gestures
|
||||
godotFragment?.godot?.renderView?.inputHandler?.apply {
|
||||
|
@ -171,17 +184,6 @@ open class GodotEditor : GodotActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for project permissions to enable
|
||||
*/
|
||||
protected open fun checkForProjectPermissionsToEnable() {
|
||||
// Check for RECORD_AUDIO permission
|
||||
val audioInputEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("audio/driver/enable_input"))
|
||||
if (audioInputEnabled) {
|
||||
PermissionsUtil.requestPermission(Manifest.permission.RECORD_AUDIO, this)
|
||||
}
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected open fun updateCommandLineParams(args: List<String>) {
|
||||
// Update the list of command line params with the new args
|
||||
|
@ -196,7 +198,7 @@ open class GodotEditor : GodotActivity() {
|
|||
|
||||
final override fun getCommandLine() = commandLineParams
|
||||
|
||||
protected open fun getEditorWindowInfo(args: Array<String>): EditorWindowInfo {
|
||||
protected open fun retrieveEditorWindowInfo(args: Array<String>): EditorWindowInfo {
|
||||
var hasEditor = false
|
||||
|
||||
var i = 0
|
||||
|
@ -273,7 +275,7 @@ open class GodotEditor : GodotActivity() {
|
|||
}
|
||||
|
||||
override fun onNewGodotInstanceRequested(args: Array<String>): Int {
|
||||
val editorWindowInfo = getEditorWindowInfo(args)
|
||||
val editorWindowInfo = retrieveEditorWindowInfo(args)
|
||||
|
||||
// Launch a new activity
|
||||
val sourceView = godotFragment?.view
|
||||
|
@ -405,20 +407,26 @@ open class GodotEditor : GodotActivity() {
|
|||
|
||||
return when (policy) {
|
||||
LaunchPolicy.AUTO -> {
|
||||
try {
|
||||
when (Integer.parseInt(GodotLib.getEditorSetting("run/window_placement/android_window"))) {
|
||||
ANDROID_WINDOW_SAME_AS_EDITOR -> LaunchPolicy.SAME
|
||||
ANDROID_WINDOW_SIDE_BY_SIDE_WITH_EDITOR -> LaunchPolicy.ADJACENT
|
||||
ANDROID_WINDOW_SAME_AS_EDITOR_AND_LAUNCH_IN_PIP_MODE -> LaunchPolicy.SAME_AND_LAUNCH_IN_PIP_MODE
|
||||
else -> {
|
||||
// ANDROID_WINDOW_AUTO
|
||||
defaultLaunchPolicy
|
||||
if (isHorizonOSDevice()) {
|
||||
// Horizon OS UX is more desktop-like and has support for launching adjacent
|
||||
// windows. So we always want to launch in adjacent mode when auto is selected.
|
||||
LaunchPolicy.ADJACENT
|
||||
} else {
|
||||
try {
|
||||
when (Integer.parseInt(GodotLib.getEditorSetting("run/window_placement/android_window"))) {
|
||||
ANDROID_WINDOW_SAME_AS_EDITOR -> LaunchPolicy.SAME
|
||||
ANDROID_WINDOW_SIDE_BY_SIDE_WITH_EDITOR -> LaunchPolicy.ADJACENT
|
||||
ANDROID_WINDOW_SAME_AS_EDITOR_AND_LAUNCH_IN_PIP_MODE -> LaunchPolicy.SAME_AND_LAUNCH_IN_PIP_MODE
|
||||
else -> {
|
||||
// ANDROID_WINDOW_AUTO
|
||||
defaultLaunchPolicy
|
||||
}
|
||||
}
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.w(TAG, "Error parsing the Android window placement editor setting", e)
|
||||
// Fall-back to the default launch policy
|
||||
defaultLaunchPolicy
|
||||
}
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.w(TAG, "Error parsing the Android window placement editor setting", e)
|
||||
// Fall-back to the default launch policy
|
||||
defaultLaunchPolicy
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,8 +439,16 @@ open class GodotEditor : GodotActivity() {
|
|||
/**
|
||||
* Returns true the if the device supports picture-in-picture (PiP)
|
||||
*/
|
||||
protected open fun hasPiPSystemFeature() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N &&
|
||||
packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
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)
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
|
@ -42,9 +42,9 @@ import android.util.Log
|
|||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
/**
|
||||
* Used by the [GodotEditor] classes to dispatch messages across processes.
|
||||
* Used by the [BaseGodotEditor] classes to dispatch messages across processes.
|
||||
*/
|
||||
internal class EditorMessageDispatcher(private val editor: GodotEditor) {
|
||||
internal class EditorMessageDispatcher(private val editor: BaseGodotEditor) {
|
||||
|
||||
companion object {
|
||||
private val TAG = EditorMessageDispatcher::class.java.simpleName
|
||||
|
@ -173,7 +173,11 @@ internal class EditorMessageDispatcher(private val editor: GodotEditor) {
|
|||
// to the sender.
|
||||
val senderId = messengerBundle.getInt(KEY_EDITOR_ID)
|
||||
val senderMessenger: Messenger? = messengerBundle.getParcelable(KEY_EDITOR_MESSENGER)
|
||||
registerMessenger(senderId, senderMessenger)
|
||||
registerMessenger(senderId, senderMessenger) {
|
||||
// Terminate current instance when parent is no longer available.
|
||||
Log.d(TAG, "Terminating current editor instance because parent is no longer available")
|
||||
editor.finish()
|
||||
}
|
||||
|
||||
// Register ourselves to the sender so that it can communicate with us.
|
||||
registerSelfTo(pm, senderMessenger, editor.getEditorWindowInfo().windowId)
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
package org.godotengine.editor
|
||||
|
||||
import android.Manifest
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.Intent
|
||||
|
@ -38,12 +39,15 @@ import android.os.Build
|
|||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import org.godotengine.godot.GodotLib
|
||||
import org.godotengine.godot.utils.PermissionsUtil
|
||||
import org.godotengine.godot.utils.ProcessPhoenix
|
||||
|
||||
/**
|
||||
* Drives the 'run project' window of the Godot Editor.
|
||||
*/
|
||||
class GodotGame : GodotEditor() {
|
||||
open class GodotGame : GodotEditor() {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotGame::class.java.simpleName
|
||||
|
@ -136,8 +140,53 @@ class GodotGame : GodotEditor() {
|
|||
|
||||
override fun enablePanAndScaleGestures() = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/pointing/android/enable_pan_and_scale_gestures"))
|
||||
|
||||
override fun checkForProjectPermissionsToEnable() {
|
||||
// Nothing to do.. by the time we get here, the project permissions will have already
|
||||
// been requested by the Editor window.
|
||||
override fun onGodotSetupCompleted() {
|
||||
super.onGodotSetupCompleted()
|
||||
Log.v(TAG, "OnGodotSetupCompleted")
|
||||
|
||||
// Check if we should be running in XR instead (if available) as it's possible we were
|
||||
// launched from the project manager which doesn't have that information.
|
||||
val launchingArgs = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||
if (launchingArgs != null) {
|
||||
val editorWindowInfo = retrieveEditorWindowInfo(launchingArgs)
|
||||
if (editorWindowInfo != getEditorWindowInfo()) {
|
||||
val relaunchIntent = getNewGodotInstanceIntent(editorWindowInfo, launchingArgs)
|
||||
relaunchIntent.putExtra(EXTRA_NEW_LAUNCH, true)
|
||||
.putExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD, intent.getBundleExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD))
|
||||
|
||||
Log.d(TAG, "Relaunching XR project using ${editorWindowInfo.windowClassName} with parameters ${launchingArgs.contentToString()}")
|
||||
val godot = godot
|
||||
if (godot != null) {
|
||||
godot.destroyAndKillProcess {
|
||||
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
|
||||
}
|
||||
} else {
|
||||
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Request project runtime permissions if necessary
|
||||
val permissionsToEnable = getProjectPermissionsToEnable()
|
||||
if (permissionsToEnable.isNotEmpty()) {
|
||||
PermissionsUtil.requestPermissions(this, permissionsToEnable)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for project permissions to enable
|
||||
*/
|
||||
@CallSuper
|
||||
protected open fun getProjectPermissionsToEnable(): MutableList<String> {
|
||||
val permissionsToEnable = mutableListOf<String>()
|
||||
|
||||
// Check for RECORD_AUDIO permission
|
||||
val audioInputEnabled = java.lang.Boolean.parseBoolean(GodotLib.getGlobal("audio/driver/enable_input"))
|
||||
if (audioInputEnabled) {
|
||||
permissionsToEnable.add(Manifest.permission.RECORD_AUDIO)
|
||||
}
|
||||
|
||||
return permissionsToEnable
|
||||
}
|
||||
}
|
||||
|
|
99
platform/android/java/editor/src/meta/AndroidManifest.xml
Normal file
99
platform/android/java/editor/src/meta/AndroidManifest.xml
Normal file
|
@ -0,0 +1,99 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:horizonos="http://schemas.horizonos/sdk">
|
||||
|
||||
<horizonos:uses-horizonos-sdk
|
||||
horizonos:minSdkVersion="69"
|
||||
horizonos:targetSdkVersion="69" />
|
||||
|
||||
<uses-feature
|
||||
android:name="android.hardware.vr.headtracking"
|
||||
android:required="true"
|
||||
android:version="1"/>
|
||||
|
||||
<!-- Oculus Quest hand tracking -->
|
||||
<uses-permission android:name="com.oculus.permission.HAND_TRACKING" />
|
||||
<uses-feature
|
||||
android:name="oculus.software.handtracking"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Passthrough feature flag -->
|
||||
<uses-feature android:name="com.oculus.feature.PASSTHROUGH"
|
||||
android:required="false" />
|
||||
|
||||
<!-- Overlay keyboard support -->
|
||||
<uses-feature android:name="oculus.software.overlay_keyboard" android:required="false"/>
|
||||
|
||||
<!-- Render model -->
|
||||
<uses-permission android:name="com.oculus.permission.RENDER_MODEL" />
|
||||
<uses-feature android:name="com.oculus.feature.RENDER_MODEL" android:required="false" />
|
||||
|
||||
<!-- Anchor api -->
|
||||
<uses-permission android:name="com.oculus.permission.USE_ANCHOR_API" />
|
||||
|
||||
<!-- Scene api -->
|
||||
<uses-permission android:name="com.oculus.permission.USE_SCENE" />
|
||||
|
||||
<application>
|
||||
|
||||
<activity
|
||||
android:name=".GodotEditor"
|
||||
android:exported="true"
|
||||
android:screenOrientation="landscape"
|
||||
tools:node="merge"
|
||||
tools:replace="android:screenOrientation">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="com.oculus.intent.category.2D" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data android:name="com.oculus.vrshell.free_resizing_lock_aspect_ratio" android:value="true"/>
|
||||
</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">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="com.oculus.intent.category.VR" />
|
||||
<category android:name="org.khronos.openxr.intent.category.IMMERSIVE_HMD" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Supported Meta devices -->
|
||||
<meta-data
|
||||
android:name="com.oculus.supportedDevices"
|
||||
android:value="quest3|questpro"
|
||||
tools:replace="android:value" />
|
||||
|
||||
<!--
|
||||
We remove this meta-data originating from the vendors plugin as we only need the loader for
|
||||
now since the project being edited provides its own version of the vendors plugin.
|
||||
|
||||
This needs to be removed once we start implementing the immersive version of the project
|
||||
manager and editor windows.
|
||||
-->
|
||||
<meta-data
|
||||
android:name="org.godotengine.plugin.v2.GodotOpenXRMeta"
|
||||
android:value="org.godotengine.openxr.vendors.meta.GodotOpenXRMeta"
|
||||
tools:node="remove" />
|
||||
|
||||
<!-- Enable system splash screen -->
|
||||
<meta-data android:name="com.oculus.ossplash" android:value="true"/>
|
||||
<!-- Enable passthrough background during the splash screen -->
|
||||
<meta-data android:name="com.oculus.ossplash.background" android:value="passthrough-contextual"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
BIN
platform/android/java/editor/src/meta/assets/vr_splash.png
Normal file
BIN
platform/android/java/editor/src/meta/assets/vr_splash.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,94 @@
|
|||
/**************************************************************************/
|
||||
/* GodotEditor.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. */
|
||||
/**************************************************************************/
|
||||
|
||||
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 Meta 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")
|
||||
|
||||
internal const val USE_ANCHOR_API_PERMISSION = "com.oculus.permission.USE_ANCHOR_API"
|
||||
internal const val USE_SCENE_PERMISSION = "com.oculus.permission.USE_SCENE"
|
||||
}
|
||||
|
||||
override fun getExcludedPermissions(): MutableSet<String> {
|
||||
val excludedPermissions = super.getExcludedPermissions()
|
||||
// The USE_ANCHOR_API and USE_SCENE permissions are requested when the "xr/openxr/enabled"
|
||||
// project setting is enabled.
|
||||
excludedPermissions.add(USE_ANCHOR_API_PERMISSION)
|
||||
excludedPermissions.add(USE_SCENE_PERMISSION)
|
||||
return excludedPermissions
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*************************************************************************/
|
||||
/* 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.utils.PermissionsUtil
|
||||
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
|
||||
|
||||
override fun getProjectPermissionsToEnable(): MutableList<String> {
|
||||
val permissionsToEnable = super.getProjectPermissionsToEnable()
|
||||
|
||||
val openxrEnabled = GodotLib.getGlobal("xr/openxr/enabled").toBoolean()
|
||||
if (openxrEnabled) {
|
||||
permissionsToEnable.add(USE_ANCHOR_API_PERMISSION)
|
||||
permissionsToEnable.add(USE_SCENE_PERMISSION)
|
||||
}
|
||||
|
||||
return permissionsToEnable
|
||||
}
|
||||
}
|
|
@ -51,7 +51,7 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
flavorDimensions "products"
|
||||
flavorDimensions = ["products"]
|
||||
productFlavors {
|
||||
editor {}
|
||||
template {}
|
||||
|
@ -104,7 +104,7 @@ android {
|
|||
}
|
||||
|
||||
boolean devBuild = buildType == "dev"
|
||||
boolean debugSymbols = devBuild || isAndroidStudio()
|
||||
boolean debugSymbols = devBuild
|
||||
boolean runTests = devBuild
|
||||
boolean productionBuild = !devBuild
|
||||
boolean storeRelease = buildType == "release"
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
package org.godotengine.godot;
|
||||
|
||||
import org.godotengine.godot.input.GodotInputHandler;
|
||||
import org.godotengine.godot.utils.DeviceUtils;
|
||||
|
||||
import android.view.SurfaceView;
|
||||
|
||||
|
@ -63,7 +64,11 @@ public interface GodotRenderView {
|
|||
|
||||
void setPointerIcon(int pointerType);
|
||||
|
||||
/**
|
||||
* @return true if pointer capture is supported.
|
||||
*/
|
||||
default boolean canCapturePointer() {
|
||||
return getInputHandler().canCapturePointer();
|
||||
// Pointer capture is not supported on Horizon OS
|
||||
return !DeviceUtils.isHorizonOSDevice() && getInputHandler().canCapturePointer();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,6 +68,7 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
|||
setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT));
|
||||
}
|
||||
setFocusableInTouchMode(true);
|
||||
setClickable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -132,17 +133,17 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
|||
|
||||
@Override
|
||||
public boolean onKeyUp(final int keyCode, KeyEvent event) {
|
||||
return mInputHandler.onKeyUp(keyCode, event);
|
||||
return mInputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onKeyDown(final int keyCode, KeyEvent event) {
|
||||
return mInputHandler.onKeyDown(keyCode, event);
|
||||
return mInputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
return mInputHandler.onGenericMotionEvent(event);
|
||||
return mInputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/**************************************************************************/
|
||||
/* 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.os.Build
|
||||
|
||||
/**
|
||||
* Returns true if running on Meta's Horizon OS.
|
||||
*/
|
||||
fun isHorizonOSDevice(): Boolean {
|
||||
return "Oculus".equals(Build.BRAND, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if running on a native Android XR device.
|
||||
*/
|
||||
fun isNativeXRDevice(): Boolean {
|
||||
return isHorizonOSDevice()
|
||||
}
|
|
@ -8,6 +8,7 @@ set(CMAKE_CXX_EXTENSIONS OFF)
|
|||
|
||||
set(GODOT_ROOT_DIR ../../../..)
|
||||
set(ANDROID_ROOT_DIR "${GODOT_ROOT_DIR}/platform/android" CACHE STRING "")
|
||||
set(OPENXR_INCLUDE_DIR "${GODOT_ROOT_DIR}/thirdparty/openxr/include" CACHE STRING "")
|
||||
|
||||
# Get sources
|
||||
file(GLOB_RECURSE SOURCES ${GODOT_ROOT_DIR}/*.c**)
|
||||
|
@ -17,6 +18,7 @@ add_executable(${PROJECT_NAME} ${SOURCES} ${HEADERS})
|
|||
target_include_directories(${PROJECT_NAME}
|
||||
SYSTEM PUBLIC
|
||||
${GODOT_ROOT_DIR}
|
||||
${ANDROID_ROOT_DIR})
|
||||
${ANDROID_ROOT_DIR}
|
||||
${OPENXR_INCLUDE_DIR})
|
||||
|
||||
add_definitions(-DUNIX_ENABLED -DVULKAN_ENABLED -DANDROID_ENABLED -DGLES3_ENABLED -DTOOLS_ENABLED)
|
||||
|
|
|
@ -14,6 +14,7 @@ pluginManagement {
|
|||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
maven { url "https://plugins.gradle.org/m2/" }
|
||||
maven { url "https://s01.oss.sonatype.org/content/repositories/snapshots/"}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "string_android.h"
|
||||
|
||||
#include "core/config/engine.h"
|
||||
#include "core/config/project_settings.h"
|
||||
#include "core/error/error_macros.h"
|
||||
|
||||
static HashMap<String, JNISingleton *> jni_singletons;
|
||||
|
@ -43,7 +42,6 @@ static HashMap<String, JNISingleton *> jni_singletons;
|
|||
void unregister_plugins_singletons() {
|
||||
for (const KeyValue<String, JNISingleton *> &E : jni_singletons) {
|
||||
Engine::get_singleton()->remove_singleton(E.key);
|
||||
ProjectSettings::get_singleton()->set(E.key, Variant());
|
||||
|
||||
if (E.value) {
|
||||
memdelete(E.value);
|
||||
|
@ -64,7 +62,6 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_plugin_GodotPlugin_nativeR
|
|||
jni_singletons[singname] = s;
|
||||
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton(singname, s));
|
||||
ProjectSettings::get_singleton()->set(singname, s);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue