feat: updated godot version
This commit is contained in:
parent
0c508b0831
commit
42b028dbb5
4694 changed files with 236470 additions and 401376 deletions
|
|
@ -27,6 +27,8 @@ allprojects {
|
|||
}
|
||||
|
||||
configurations {
|
||||
// Initializes a placeholder for the devImplementation dependency configuration.
|
||||
devImplementation {}
|
||||
// Initializes a placeholder for the monoImplementation dependency configuration.
|
||||
monoImplementation {}
|
||||
}
|
||||
|
|
@ -51,32 +53,15 @@ dependencies {
|
|||
// Godot gradle build mode. In this scenario this project is the only one around and the Godot
|
||||
// library is available through the pre-generated godot-lib.*.aar android archive files.
|
||||
debugImplementation fileTree(dir: 'libs/debug', include: ['**/*.jar', '*.aar'])
|
||||
devImplementation fileTree(dir: 'libs/dev', include: ['**/*.jar', '*.aar'])
|
||||
releaseImplementation fileTree(dir: 'libs/release', include: ['**/*.jar', '*.aar'])
|
||||
}
|
||||
|
||||
// Godot user plugins remote dependencies
|
||||
String[] remoteDeps = getGodotPluginsRemoteBinaries()
|
||||
if (remoteDeps != null && remoteDeps.size() > 0) {
|
||||
def platformPattern = /^\s*(platform|enforcedPlatform)\s*\(\s*['"]*(\S+)['"]*\s*\)$/
|
||||
for (String dep : remoteDeps) {
|
||||
def matcher = dep =~ platformPattern
|
||||
if (matcher) {
|
||||
switch (matcher[0][1]) {
|
||||
case "platform":
|
||||
implementation platform(matcher[0][2])
|
||||
break
|
||||
|
||||
case "enforcedPlatform":
|
||||
implementation enforcedPlatform(matcher[0][2])
|
||||
break
|
||||
|
||||
default:
|
||||
throw new GradleException("Invalid remote platform dependency: $dep")
|
||||
break
|
||||
}
|
||||
} else {
|
||||
implementation dep
|
||||
}
|
||||
implementation dep
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -221,6 +206,18 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
dev {
|
||||
initWith debug
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for Godot gradle builds.
|
||||
zipAlignEnabled shouldZipAlign()
|
||||
if (shouldSign()) {
|
||||
signingConfig signingConfigs.debug
|
||||
} else {
|
||||
signingConfig null
|
||||
}
|
||||
}
|
||||
|
||||
release {
|
||||
// Signing and zip-aligning are skipped for prebuilt builds, but
|
||||
// performed for Godot gradle builds.
|
||||
|
|
@ -254,6 +251,7 @@ android {
|
|||
sourceSets {
|
||||
main.res.srcDirs += ['res']
|
||||
debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
|
||||
dev.jniLibs.srcDirs = ['libs/dev']
|
||||
release.jniLibs.srcDirs = ['libs/release']
|
||||
}
|
||||
|
||||
|
|
@ -332,6 +330,9 @@ module, so we're ensuring the ':app:preBuild' task is set to run after those tas
|
|||
if (rootProject.tasks.findByPath("copyDebugAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyDebugAARToAppModule"))
|
||||
}
|
||||
if (rootProject.tasks.findByPath("copyDevAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyDevAARToAppModule"))
|
||||
}
|
||||
if (rootProject.tasks.findByPath("copyReleaseAARToAppModule") != null) {
|
||||
preBuild.mustRunAfter(rootProject.tasks.named("copyReleaseAARToAppModule"))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
ext.versions = [
|
||||
androidGradlePlugin: '8.6.1',
|
||||
compileSdk : 36,
|
||||
compileSdk : 35,
|
||||
// Also update:
|
||||
// - 'platform/android/export/export_plugin.cpp#DEFAULT_MIN_SDK_VERSION'
|
||||
// - 'platform/android/detect.py#get_min_target_api()'
|
||||
minSdk : 24,
|
||||
// Also update 'platform/android/export/export_plugin.cpp#DEFAULT_TARGET_SDK_VERSION'
|
||||
targetSdk : 36,
|
||||
buildTools : '36.1.0',
|
||||
kotlinVersion : '2.1.21',
|
||||
targetSdk : 35,
|
||||
buildTools : '35.0.1',
|
||||
kotlinVersion : '2.1.20',
|
||||
fragmentVersion : '1.8.6',
|
||||
nexusPublishVersion: '1.3.0',
|
||||
javaVersion : JavaVersion.VERSION_17,
|
||||
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
|
||||
ndkVersion : '29.0.14206865',
|
||||
ndkVersion : '28.1.13356709',
|
||||
splashscreenVersion: '1.0.1',
|
||||
// 'openxrLoaderVersion' should be set to XR_CURRENT_API_VERSION, see 'thirdparty/openxr'
|
||||
openxrLoaderVersion: '1.1.53',
|
||||
openxrVendorsVersion: '4.3.0-stable',
|
||||
openxrVendorsVersion: '4.2.2-stable',
|
||||
junitVersion : '1.3.0',
|
||||
espressoCoreVersion: '3.7.0',
|
||||
kotlinTestVersion : '1.3.11',
|
||||
|
|
|
|||
|
|
@ -1,4 +1,12 @@
|
|||
list=[{
|
||||
"base": &"RefCounted",
|
||||
"class": &"BaseTest",
|
||||
"icon": "",
|
||||
"is_abstract": true,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/base_test.gd"
|
||||
}, {
|
||||
"base": &"BaseTest",
|
||||
"class": &"FileAccessTests",
|
||||
"icon": "",
|
||||
|
|
@ -14,12 +22,4 @@ list=[{
|
|||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/javaclasswrapper/java_class_wrapper_tests.gd"
|
||||
}, {
|
||||
"base": &"RefCounted",
|
||||
"class": &"BaseTest",
|
||||
"icon": "",
|
||||
"is_abstract": true,
|
||||
"is_tool": false,
|
||||
"language": &"GDScript",
|
||||
"path": "res://test/base_test.gd"
|
||||
}]
|
||||
|
|
|
|||
|
|
@ -1,29 +1,29 @@
|
|||
[gd_scene format=3 uid="uid://cg3hylang5fxn"]
|
||||
[gd_scene load_steps=2 format=3 uid="uid://cg3hylang5fxn"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bv6y7in6otgcm" path="res://main.gd" id="1_j0gfq"]
|
||||
|
||||
[node name="Main" type="Node2D" unique_id=852911723]
|
||||
[node name="Main" type="Node2D"]
|
||||
script = ExtResource("1_j0gfq")
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=1839352715]
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="."]
|
||||
offset_left = 68.0
|
||||
offset_top = 102.0
|
||||
offset_right = 506.0
|
||||
offset_bottom = 408.0
|
||||
theme_override_constants/separation = 25
|
||||
|
||||
[node name="PluginToastButton" type="Button" parent="VBoxContainer" unique_id=1670434164]
|
||||
[node name="PluginToastButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "Plugin Toast
|
||||
"
|
||||
|
||||
[node name="VibrationButton" type="Button" parent="VBoxContainer" unique_id=648980813]
|
||||
[node name="VibrationButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "Vibration"
|
||||
|
||||
[node name="GDScriptToastButton" type="Button" parent="VBoxContainer" unique_id=95554078]
|
||||
[node name="GDScriptToastButton" type="Button" parent="VBoxContainer"]
|
||||
custom_minimum_size = Vector2(0, 50)
|
||||
layout_mode = 2
|
||||
text = "GDScript Toast
|
||||
|
|
|
|||
|
|
@ -8,15 +8,11 @@
|
|||
|
||||
config_version=5
|
||||
|
||||
[animation]
|
||||
|
||||
compatibility/default_parent_skeleton_in_mesh_instance_3d=true
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Godot App Instrumentation Tests"
|
||||
run/main_scene="res://main.tscn"
|
||||
config/features=PackedStringArray("4.6", "GL Compatibility")
|
||||
config/features=PackedStringArray("4.5", "GL Compatibility")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[debug]
|
||||
|
|
|
|||
|
|
@ -20,10 +20,6 @@ func run_tests():
|
|||
|
||||
__exec_test(test_callable)
|
||||
|
||||
__exec_test(test_interface_callable_proxy)
|
||||
|
||||
__exec_test(test_interface_object_proxy)
|
||||
|
||||
print("JavaClassWrapper tests finished.")
|
||||
print("Tests started: " + str(_test_started))
|
||||
print("Tests completed: " + str(_test_completed))
|
||||
|
|
@ -173,34 +169,3 @@ func test_callable() -> bool:
|
|||
assert_equal(cb1_data['called'], true)
|
||||
|
||||
return true
|
||||
|
||||
func test_interface_callable_proxy() -> bool:
|
||||
var cb1_data := {called = false, content = ""}
|
||||
var cb1 = func (content: String) -> void:
|
||||
cb1_data['called'] = true
|
||||
cb1_data['content'] = content
|
||||
|
||||
var printer_proxy = JavaClassWrapper.create_sam_callback("android.util.Printer", cb1)
|
||||
assert_true(printer_proxy != null)
|
||||
|
||||
printer_proxy.println("This is a callback test")
|
||||
assert_equal(cb1_data['called'], true)
|
||||
assert_equal(cb1_data['content'], "This is a callback test")
|
||||
return true
|
||||
|
||||
class PrintProxy:
|
||||
var test_data := {called = false, content = ""}
|
||||
|
||||
func println(content: String) -> void:
|
||||
test_data['called'] = true
|
||||
test_data['content'] = content
|
||||
|
||||
func test_interface_object_proxy() -> bool:
|
||||
var print_object = PrintProxy.new()
|
||||
var proxy = JavaClassWrapper.create_proxy(print_object, ["android.util.Printer"])
|
||||
assert_true(proxy != null)
|
||||
|
||||
proxy.println("This is proxy test")
|
||||
assert_equal(print_object.test_data['called'], true)
|
||||
assert_equal(print_object.test_data['content'], "This is proxy test")
|
||||
return true
|
||||
|
|
|
|||
|
|
@ -35,7 +35,6 @@
|
|||
android:launchMode="singleInstancePerTask"
|
||||
android:excludeFromRecents="false"
|
||||
android:exported="false"
|
||||
android:supportsPictureInPicture="true"
|
||||
android:screenOrientation="landscape"
|
||||
android:windowSoftInputMode="adjustResize"
|
||||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
|
|
|
|||
|
|
@ -92,9 +92,4 @@ public class GodotApp extends GodotActivity {
|
|||
super.onGodotForceQuit(instance);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPiPEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ ext {
|
|||
supportedFlavors = ["editor", "template"]
|
||||
supportedAndroidDistributions = ["android", "horizonos", "picoos"]
|
||||
supportedFlavorsBuildTypes = [
|
||||
"editor": ["debug", "release"],
|
||||
"template": ["debug", "release"]
|
||||
"editor": ["dev", "debug", "release"],
|
||||
"template": ["dev", "debug", "release"]
|
||||
]
|
||||
supportedEditions = ["standard", "mono"]
|
||||
|
||||
|
|
@ -50,11 +50,11 @@ def getSconsTaskName(String flavor, String buildType, String abi) {
|
|||
|
||||
/**
|
||||
* Generate Godot gradle build template by zipping the source files from the app directory, as well
|
||||
* as the AAR files generated by 'copyDebugAAR' and 'copyReleaseAAR'.
|
||||
* as the AAR files generated by 'copyDebugAAR', 'copyDevAAR' and 'copyReleaseAAR'.
|
||||
* The zip file also includes some gradle tools to enable gradle builds from the Godot Editor.
|
||||
*/
|
||||
task zipGradleBuild(type: Zip) {
|
||||
onlyIf { generateGodotTemplates.state.executed || generateGodotMonoTemplates.state.executed }
|
||||
onlyIf { generateGodotTemplates.state.executed || generateGodotMonoTemplates.state.executed || generateDevTemplate.state.executed }
|
||||
doFirst {
|
||||
logger.lifecycle("Generating Godot gradle build template")
|
||||
}
|
||||
|
|
@ -124,6 +124,9 @@ def generateBuildTasks(String flavor = "template", String edition = "standard",
|
|||
File targetLibs = new File(libsDir + target)
|
||||
|
||||
String targetSuffix = target
|
||||
if (target == "dev") {
|
||||
targetSuffix = "debug.dev"
|
||||
}
|
||||
|
||||
if (!excludeSconsBuildTasks || (targetLibs != null
|
||||
&& targetLibs.isDirectory()
|
||||
|
|
@ -312,20 +315,26 @@ task cleanGodotTemplates(type: Delete) {
|
|||
|
||||
// Delete the Godot templates in the Godot bin directory
|
||||
delete("$binDir/android_debug.apk")
|
||||
delete("$binDir/android_dev.apk")
|
||||
delete("$binDir/android_release.apk")
|
||||
delete("$binDir/android_monoDebug.apk")
|
||||
delete("$binDir/android_monoDev.apk")
|
||||
delete("$binDir/android_monoRelease.apk")
|
||||
delete("$binDir/android_source.zip")
|
||||
delete("$binDir/godot-lib.template_debug.aar")
|
||||
delete("$binDir/godot-lib.template_debug.dev.aar")
|
||||
delete("$binDir/godot-lib.template_release.aar")
|
||||
|
||||
// Cover deletion for the libs using the previous naming scheme
|
||||
delete("$binDir/godot-lib.debug.aar")
|
||||
delete("$binDir/godot-lib.dev.aar")
|
||||
delete("$binDir/godot-lib.release.aar")
|
||||
|
||||
// Delete the native debug symbols files.
|
||||
delete("$binDir/android-editor-debug-native-symbols.zip")
|
||||
delete("$binDir/android-editor-dev-native-symbols.zip")
|
||||
delete("$binDir/android-editor-release-native-symbols.zip")
|
||||
delete("$binDir/android-template-debug-native-symbols.zip")
|
||||
delete("$binDir/android-template-dev-native-symbols.zip")
|
||||
delete("$binDir/android-template-release-native-symbols.zip")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ android {
|
|||
applicationId "org.godotengine.editor.v4"
|
||||
versionCode generateVersionCode()
|
||||
versionName generateVersionName()
|
||||
minSdkVersion 29 // Minimum recommended sdk version for Vulkan 1.1 support. See https://developer.android.com/games/develop/vulkan/native-engine-support#recommendations
|
||||
minSdkVersion versions.minSdk
|
||||
targetSdkVersion versions.targetSdk
|
||||
|
||||
missingDimensionStrategy 'products', 'editor'
|
||||
|
|
@ -131,7 +131,14 @@ android {
|
|||
}
|
||||
|
||||
buildTypes {
|
||||
dev {
|
||||
initWith debug
|
||||
applicationIdSuffix ".dev"
|
||||
manifestPlaceholders += [editorBuildSuffix: " (dev)"]
|
||||
}
|
||||
|
||||
debug {
|
||||
initWith release
|
||||
applicationIdSuffix ".debug"
|
||||
manifestPlaceholders += [editorBuildSuffix: " (debug)"]
|
||||
signingConfig signingConfigs.debug
|
||||
|
|
@ -140,14 +147,6 @@ android {
|
|||
release {
|
||||
if (hasReleaseSigningConfigs()) {
|
||||
signingConfig signingConfigs.release
|
||||
} else {
|
||||
// We default to the debug signingConfigs when the release signing configs are not
|
||||
// available (e.g: development in Android Studio).
|
||||
signingConfig signingConfigs.debug
|
||||
// In addition, we update the application ID to allow installing an Android studio release build
|
||||
// side by side with a production build from the store.
|
||||
applicationIdSuffix ".release"
|
||||
manifestPlaceholders += [editorBuildSuffix: " (release)"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -187,6 +186,7 @@ android {
|
|||
}
|
||||
applicationIdSuffix ".pico"
|
||||
versionNameSuffix "-pico"
|
||||
minSdkVersion 29
|
||||
targetSdkVersion 32
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,14 +16,6 @@
|
|||
<uses-feature
|
||||
android:glEsVersion="0x00030000"
|
||||
android:required="true" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.vulkan.version"
|
||||
android:required="true"
|
||||
android:version="0x401000" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.vulkan.level"
|
||||
android:required="true"
|
||||
android:version="1" />
|
||||
<uses-feature
|
||||
android:name="android.hardware.camera"
|
||||
android:required="false" />
|
||||
|
|
@ -60,7 +52,7 @@
|
|||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||
android:exported="false"
|
||||
android:icon="@mipmap/themed_icon"
|
||||
android:launchMode="singleInstancePerTask"
|
||||
android:launchMode="singleTask"
|
||||
android:screenOrientation="userLandscape">
|
||||
<layout
|
||||
android:defaultWidth="@dimen/editor_default_window_width"
|
||||
|
|
@ -93,15 +85,6 @@
|
|||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="file" />
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="*/*" />
|
||||
<data android:host="*" />
|
||||
<data android:pathPattern=".*\\.godot" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
<activity
|
||||
android:name=".GodotGame"
|
||||
|
|
|
|||
|
|
@ -34,12 +34,9 @@ import android.Manifest
|
|||
import android.app.ActivityManager
|
||||
import android.app.ActivityOptions
|
||||
import android.content.ComponentName
|
||||
import android.content.ContentResolver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Debug
|
||||
|
|
@ -74,9 +71,7 @@ import org.godotengine.godot.utils.DialogUtils
|
|||
import org.godotengine.godot.utils.PermissionsUtil
|
||||
import org.godotengine.godot.utils.ProcessPhoenix
|
||||
import org.godotengine.openxr.vendors.utils.*
|
||||
import java.io.File
|
||||
import kotlin.math.min
|
||||
import kotlin.text.indexOf
|
||||
|
||||
/**
|
||||
* Base class for the Godot Android Editor activities.
|
||||
|
|
@ -157,7 +152,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
internal const val GAME_MENU_ACTION_SET_TIME_SCALE = "setTimeScale"
|
||||
|
||||
private const val GAME_WORKSPACE = "Game"
|
||||
private const val SCRIPT_WORKSPACE = "Script"
|
||||
|
||||
internal const val SNACKBAR_SHOW_DURATION_MS = 5000L
|
||||
|
||||
|
|
@ -204,12 +198,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
protected var gameMenuFragment: GameMenuFragment? = null
|
||||
protected val gameMenuState = Bundle()
|
||||
|
||||
private val updatedCommandLineParams = ArrayList<String>()
|
||||
|
||||
private var changingOrientationAllowed = false
|
||||
private var distractionFreeModeEnabled = false
|
||||
private var activeWorkspace: String? = null
|
||||
|
||||
override fun getGodotAppLayout() = R.layout.godot_editor_layout
|
||||
|
||||
internal open fun getEditorWindowInfo() = EDITOR_MAIN_INFO
|
||||
|
|
@ -256,7 +244,8 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
|
||||
// Skip permissions request if running in a device farm (e.g. firebase test lab) or if requested via the launch
|
||||
// intent (e.g. instrumentation tests).
|
||||
val skipPermissionsRequest = isRunningInInstrumentation() || ActivityManager.isRunningInUserTestHarness()
|
||||
val skipPermissionsRequest = isRunningInInstrumentation() ||
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && ActivityManager.isRunningInUserTestHarness()
|
||||
if (!skipPermissionsRequest) {
|
||||
// We exclude certain permissions from the set we request at startup, as they'll be
|
||||
// requested on demand based on use cases.
|
||||
|
|
@ -265,7 +254,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
|
||||
editorMessageDispatcher.parseStartIntent(packageManager, intent)
|
||||
|
||||
if (BuildConfig.BUILD_TYPE == "debug" && WAIT_FOR_DEBUGGER) {
|
||||
if (BuildConfig.BUILD_TYPE == "dev" && WAIT_FOR_DEBUGGER) {
|
||||
Debug.waitForDebugger()
|
||||
}
|
||||
|
||||
|
|
@ -275,14 +264,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
setupGameMenuBar()
|
||||
}
|
||||
|
||||
override fun onConfigurationChanged(newConfig: Configuration) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
// Show EditorTitleBar on small screens only in landscape due to width limitations in portrait.
|
||||
// TODO: Enable for portrait once the title bar width is optimized.
|
||||
EditorUtils.toggleTitleBar(isLargeScreen || newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
gradleBuildProvider.buildEnvDisconnect()
|
||||
super.onDestroy()
|
||||
|
|
@ -338,91 +319,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
super.onNewIntent(newIntent)
|
||||
}
|
||||
|
||||
override fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
|
||||
when (intent.action) {
|
||||
Intent.ACTION_VIEW -> {
|
||||
val rootDir = Environment.getExternalStorageDirectory().canonicalPath
|
||||
|
||||
val dataPath = when (intent.scheme) {
|
||||
ContentResolver.SCHEME_FILE -> {
|
||||
intent.data?.path
|
||||
}
|
||||
|
||||
ContentResolver.SCHEME_CONTENT -> {
|
||||
// This approach is not recommend with 'content' scheme, but we require the filesystem path in
|
||||
// order to open its parent directory and load the project.
|
||||
val uriPath = intent.data?.path
|
||||
if (uriPath != null) {
|
||||
// Try and see if the external storage directory is part of the uri path.
|
||||
val rootDirIndex = uriPath.indexOf(rootDir)
|
||||
if (rootDirIndex != -1) {
|
||||
uriPath.substring(rootDirIndex)
|
||||
} else {
|
||||
// Try and see if we can retrieve an existing relative path.
|
||||
val pathParts = uriPath.split(':', '/')
|
||||
var currentPath = ""
|
||||
for (index in pathParts.size -1 downTo 0) {
|
||||
currentPath = if (currentPath == "") {
|
||||
pathParts[index]
|
||||
} else {
|
||||
"${pathParts[index]}/$currentPath"
|
||||
}
|
||||
val currentFile = File(rootDir, currentPath)
|
||||
if (currentFile.exists()) {
|
||||
break
|
||||
}
|
||||
}
|
||||
currentPath
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (!dataPath.isNullOrBlank()) {
|
||||
var dataFile = File(dataPath)
|
||||
if (!dataFile.isAbsolute) {
|
||||
dataFile = File(rootDir, dataPath)
|
||||
}
|
||||
|
||||
val dataDir = dataFile.parentFile
|
||||
if (dataDir?.isDirectory == true) {
|
||||
val loadProjectArgs = arrayOf(EDITOR_ARG, PATH_ARG, dataDir.absolutePath)
|
||||
if (newLaunch) {
|
||||
// Update the command line parameters to load the specified project.
|
||||
updatedCommandLineParams.addAll(loadProjectArgs)
|
||||
} else {
|
||||
// Check if we are already editing the specified directory.
|
||||
var isEditor = false
|
||||
var nextIsPath = false
|
||||
var currentPath = ""
|
||||
for (arg in commandLine) {
|
||||
if (nextIsPath) {
|
||||
currentPath = arg
|
||||
nextIsPath = false
|
||||
}
|
||||
|
||||
if (arg == EDITOR_ARG || arg == EDITOR_ARG_SHORT) {
|
||||
isEditor = true
|
||||
} else if (arg == PATH_ARG) {
|
||||
nextIsPath = true
|
||||
}
|
||||
}
|
||||
if (!isEditor || currentPath != dataDir.absolutePath) {
|
||||
onNewGodotInstanceRequested(loadProjectArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.handleStartIntent(intent, newLaunch)
|
||||
}
|
||||
|
||||
protected open fun shouldShowGameMenuBar() = gameMenuContainer != null
|
||||
|
||||
private fun setupGameMenuBar() {
|
||||
|
|
@ -449,7 +345,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
val longPressEnabled = enableLongPressGestures()
|
||||
val panScaleEnabled = enablePanAndScaleGestures()
|
||||
val overrideVolumeButtonsEnabled = overrideVolumeButtons()
|
||||
val hapticEnabled = enableHapticOnLongPress()
|
||||
|
||||
runOnUiThread {
|
||||
// Enable long press, panning and scaling gestures
|
||||
|
|
@ -457,7 +352,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
enableLongPress(longPressEnabled)
|
||||
enablePanningAndScalingGestures(panScaleEnabled)
|
||||
setOverrideVolumeButtons(overrideVolumeButtonsEnabled)
|
||||
enableHapticFeedback(hapticEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -510,10 +404,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
|
||||
override fun getCommandLine(): MutableList<String> {
|
||||
val params = super.getCommandLine()
|
||||
if (updatedCommandLineParams.isNotEmpty()) {
|
||||
params.addAll(updatedCommandLineParams)
|
||||
}
|
||||
if (BuildConfig.BUILD_TYPE == "debug" && !params.contains("--benchmark")) {
|
||||
if (BuildConfig.BUILD_TYPE == "dev" && !params.contains("--benchmark")) {
|
||||
params.add("--benchmark")
|
||||
}
|
||||
return params
|
||||
|
|
@ -712,7 +603,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
/**
|
||||
* The Godot Android Editor sets its own orientation via its AndroidManifest
|
||||
*/
|
||||
protected open fun overrideOrientationRequest() = !changingOrientationAllowed
|
||||
protected open fun overrideOrientationRequest() = true
|
||||
|
||||
protected open fun overrideVolumeButtons() = false
|
||||
|
||||
|
|
@ -722,12 +613,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
protected open fun enableLongPressGestures() =
|
||||
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_long_press_as_right_click"))
|
||||
|
||||
/**
|
||||
* Enable haptic feedback on long-press right-click for the Godot Android editor.
|
||||
*/
|
||||
protected open fun enableHapticOnLongPress() =
|
||||
java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/haptic_on_long_press"))
|
||||
|
||||
/**
|
||||
* Disable scroll deadzone for the Godot Android editor.
|
||||
*/
|
||||
|
|
@ -804,7 +689,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
}
|
||||
|
||||
PermissionsUtil.REQUEST_INSTALL_PACKAGES_REQ_CODE -> {
|
||||
if (!packageManager.canRequestPackageInstalls()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !packageManager.canRequestPackageInstalls()) {
|
||||
Toast.makeText(
|
||||
this,
|
||||
R.string.denied_install_packages_permission_error_msg,
|
||||
|
|
@ -916,8 +801,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
}
|
||||
|
||||
override fun onEditorWorkspaceSelected(workspace: String) {
|
||||
activeWorkspace = workspace
|
||||
|
||||
if (workspace == GAME_WORKSPACE && shouldShowGameMenuBar()) {
|
||||
if (editorMessageDispatcher.bringEditorWindowToFront(EMBEDDED_RUN_GAME_INFO) || editorMessageDispatcher.bringEditorWindowToFront(RUN_GAME_INFO)) {
|
||||
return
|
||||
|
|
@ -930,23 +813,6 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||
embeddedGameViewContainerWindow?.isVisible = true
|
||||
}
|
||||
}
|
||||
|
||||
toggleScriptEditorOrientation()
|
||||
}
|
||||
|
||||
override fun onDistractionFreeModeChanged(enabled: Boolean) {
|
||||
distractionFreeModeEnabled = enabled
|
||||
toggleScriptEditorOrientation()
|
||||
}
|
||||
|
||||
private fun toggleScriptEditorOrientation() {
|
||||
if (activeWorkspace == SCRIPT_WORKSPACE && distractionFreeModeEnabled) {
|
||||
changingOrientationAllowed = true
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
} else if (changingOrientationAllowed) {
|
||||
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE
|
||||
changingOrientationAllowed = false
|
||||
}
|
||||
}
|
||||
|
||||
internal open fun bringSelfToFront() {
|
||||
|
|
|
|||
|
|
@ -30,7 +30,12 @@
|
|||
|
||||
package org.godotengine.editor
|
||||
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.core.view.isVisible
|
||||
|
|
@ -50,6 +55,7 @@ open class GodotGame : BaseGodotGame() {
|
|||
private val TAG = GodotGame::class.java.simpleName
|
||||
}
|
||||
|
||||
private val gameViewSourceRectHint = Rect()
|
||||
private val expandGameMenuButton: View? by lazy { findViewById(R.id.game_menu_expand_button) }
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
|
@ -69,6 +75,13 @@ open class GodotGame : BaseGodotGame() {
|
|||
gameMenuFragment?.expandGameMenu()
|
||||
}
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val gameView = findViewById<View>(R.id.godot_fragment_container)
|
||||
gameView?.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
|
||||
gameView.getGlobalVisibleRect(gameViewSourceRectHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getCommandLine(): MutableList<String> {
|
||||
|
|
@ -83,7 +96,27 @@ open class GodotGame : BaseGodotGame() {
|
|||
return updatedArgs
|
||||
}
|
||||
|
||||
override fun isPiPEnabled() = true
|
||||
override fun enterPiPMode() {
|
||||
if (hasPiPSystemFeature()) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val builder = PictureInPictureParams.Builder().setSourceRectHint(gameViewSourceRectHint)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
builder.setSeamlessResizeEnabled(false)
|
||||
}
|
||||
setPictureInPictureParams(builder.build())
|
||||
}
|
||||
|
||||
Log.v(TAG, "Entering PiP mode")
|
||||
enterPictureInPictureMode()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true the if the device supports picture-in-picture (PiP).
|
||||
*/
|
||||
protected fun hasPiPSystemFeature(): Boolean {
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
}
|
||||
|
||||
override fun shouldShowGameMenuBar(): Boolean {
|
||||
return intent.getBooleanExtra(
|
||||
|
|
@ -94,11 +127,21 @@ open class GodotGame : BaseGodotGame() {
|
|||
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||
Log.v(TAG, "onPictureInPictureModeChanged: $isInPictureInPictureMode")
|
||||
|
||||
// Hide the game menu fragment when in PiP.
|
||||
gameMenuContainer?.isVisible = !isInPictureInPictureMode
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
if (isInPictureInPictureMode && !isFinishing) {
|
||||
// We get in this state when PiP is closed, so we terminate the activity.
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getGodotAppLayout() = R.layout.godot_game_layout
|
||||
|
||||
override fun getEditorWindowInfo() = RUN_GAME_INFO
|
||||
|
|
@ -215,7 +258,7 @@ open class GodotGame : BaseGodotGame() {
|
|||
|
||||
override fun isCloseButtonEnabled() = !isHorizonOSDevice(applicationContext)
|
||||
|
||||
override fun isPiPButtonEnabled() = isPiPModeSupported()
|
||||
override fun isPiPButtonEnabled() = hasPiPSystemFeature()
|
||||
|
||||
override fun isMenuBarCollapsable() = true
|
||||
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ class EmbeddedGodotGame : GodotGame() {
|
|||
|
||||
override fun isMenuBarCollapsable() = false
|
||||
|
||||
override fun isAlwaysOnTopSupported() = isPiPModeSupported()
|
||||
override fun isAlwaysOnTopSupported() = hasPiPSystemFeature()
|
||||
|
||||
override fun onFullScreenUpdated(enabled: Boolean) {
|
||||
godot?.enableImmersiveMode(enabled)
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ import androidx.fragment.app.Fragment
|
|||
import org.godotengine.editor.BaseGodotEditor
|
||||
import org.godotengine.editor.BaseGodotEditor.Companion.SNACKBAR_SHOW_DURATION_MS
|
||||
import org.godotengine.editor.R
|
||||
import org.godotengine.godot.feature.PictureInPictureProvider
|
||||
import org.godotengine.godot.utils.DialogUtils
|
||||
|
||||
/**
|
||||
|
|
@ -66,7 +65,7 @@ class GameMenuFragment : Fragment(), PopupMenu.OnMenuItemClickListener {
|
|||
/**
|
||||
* Used to be notified of events fired when interacting with the game menu.
|
||||
*/
|
||||
interface GameMenuListener : PictureInPictureProvider {
|
||||
interface GameMenuListener {
|
||||
|
||||
/**
|
||||
* Kotlin representation of the RuntimeNodeSelect::SelectMode enum in 'scene/debugger/scene_debugger.h'.
|
||||
|
|
@ -110,6 +109,7 @@ class GameMenuFragment : Fragment(), PopupMenu.OnMenuItemClickListener {
|
|||
fun isGameEmbeddingSupported(): Boolean
|
||||
fun embedGameOnPlay(embedded: Boolean)
|
||||
|
||||
fun enterPiPMode() {}
|
||||
fun minimizeGameWindow() {}
|
||||
fun closeGameWindow() {}
|
||||
|
||||
|
|
@ -181,7 +181,10 @@ class GameMenuFragment : Fragment(), PopupMenu.OnMenuItemClickListener {
|
|||
PopupMenu(context, optionsButton).apply {
|
||||
setOnMenuItemClickListener(this@GameMenuFragment)
|
||||
inflate(R.menu.options_menu)
|
||||
menu.setGroupDividerEnabled(true)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
menu.setGroupDividerEnabled(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,12 @@ android {
|
|||
buildConfig = true
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
dev {
|
||||
initWith debug
|
||||
}
|
||||
}
|
||||
|
||||
flavorDimensions = ["products"]
|
||||
productFlavors {
|
||||
editor {}
|
||||
|
|
@ -73,11 +79,13 @@ android {
|
|||
|
||||
sourceSets {
|
||||
debug.jniLibs.srcDirs = ['libs/debug']
|
||||
dev.jniLibs.srcDirs = ['libs/dev']
|
||||
release.jniLibs.srcDirs = ['libs/release']
|
||||
|
||||
// Editor jni library
|
||||
editorRelease.jniLibs.srcDirs = ['libs/tools/release']
|
||||
editorDebug.jniLibs.srcDirs = ['libs/tools/debug']
|
||||
editorDev.jniLibs.srcDirs = ['libs/tools/dev']
|
||||
}
|
||||
|
||||
libraryVariants.all { variant ->
|
||||
|
|
@ -91,9 +99,9 @@ android {
|
|||
throw new GradleException("Invalid build type: $buildType")
|
||||
}
|
||||
|
||||
boolean debugBuild = buildType == "debug"
|
||||
boolean debugSymbols = debugBuild
|
||||
boolean runTests = debugBuild
|
||||
boolean devBuild = buildType == "dev"
|
||||
boolean debugSymbols = devBuild
|
||||
boolean runTests = devBuild
|
||||
boolean storeRelease = buildType == "release"
|
||||
boolean productionBuild = storeRelease
|
||||
|
||||
|
|
@ -101,13 +109,12 @@ android {
|
|||
if (sconsTarget == "template") {
|
||||
// Tests are not supported on template builds
|
||||
runTests = false
|
||||
|
||||
//noinspection GroovyFallthrough
|
||||
switch (buildType) {
|
||||
case "release":
|
||||
sconsTarget += "_release"
|
||||
break
|
||||
case "debug":
|
||||
case "dev":
|
||||
default:
|
||||
sconsTarget += "_debug"
|
||||
break
|
||||
|
|
@ -116,6 +123,9 @@ android {
|
|||
|
||||
// Update the name of the generated library
|
||||
def outputSuffix = "${sconsTarget}"
|
||||
if (devBuild) {
|
||||
outputSuffix = "${outputSuffix}.dev"
|
||||
}
|
||||
variant.outputs.all { output ->
|
||||
output.outputFileName = "godot-lib.${outputSuffix}.aar"
|
||||
}
|
||||
|
|
@ -158,7 +168,7 @@ android {
|
|||
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
|
||||
tasks.create(name: taskName, type: Exec) {
|
||||
executable sconsExecutableFile.absolutePath
|
||||
args "--directory=${pathToRootDir}", "platform=android", "store_release=${storeRelease}", "production=${productionBuild}", "dev_mode=${debugBuild}", "dev_build=${debugBuild}", "debug_symbols=${debugSymbols}", "tests=${runTests}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
|
||||
args "--directory=${pathToRootDir}", "platform=android", "store_release=${storeRelease}", "production=${productionBuild}", "dev_mode=${devBuild}", "dev_build=${devBuild}", "debug_symbols=${debugSymbols}", "tests=${runTests}", "target=${sconsTarget}", "arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
|
||||
}
|
||||
|
||||
// Schedule the tasks so the generated libs are present before the aar file is packaged.
|
||||
|
|
|
|||
|
|
@ -43,7 +43,6 @@ import android.hardware.Sensor
|
|||
import android.hardware.SensorManager
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.util.Rational
|
||||
import android.util.TypedValue
|
||||
import android.view.*
|
||||
import android.widget.FrameLayout
|
||||
|
|
@ -58,7 +57,6 @@ import androidx.core.view.WindowInsetsCompat
|
|||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.google.android.vending.expansion.downloader.*
|
||||
import org.godotengine.godot.error.Error
|
||||
import org.godotengine.godot.feature.PictureInPictureProvider
|
||||
import org.godotengine.godot.input.GodotEditText
|
||||
import org.godotengine.godot.input.GodotInputHandler
|
||||
import org.godotengine.godot.io.FilePicker
|
||||
|
|
@ -177,6 +175,7 @@ class Godot private constructor(val context: Context) {
|
|||
*/
|
||||
private var renderViewInitialized = false
|
||||
private var primaryHost: GodotHost? = null
|
||||
private var currentConfig = context.resources.configuration
|
||||
|
||||
/**
|
||||
* Tracks whether we're in the RESUMED lifecycle state.
|
||||
|
|
@ -198,7 +197,6 @@ class Godot private constructor(val context: Context) {
|
|||
private var useDebugOpengl = false
|
||||
private var darkMode = false
|
||||
private var backgroundColor: Int = Color.BLACK
|
||||
private var orientation = Configuration.ORIENTATION_UNDEFINED
|
||||
|
||||
internal var containerLayout: FrameLayout? = null
|
||||
var renderView: GodotRenderView? = null
|
||||
|
|
@ -236,9 +234,7 @@ class Godot private constructor(val context: Context) {
|
|||
|
||||
Log.v(TAG, "InitEngine with params: $commandLineParams")
|
||||
|
||||
val config = context.resources.configuration
|
||||
darkMode = (config.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
|
||||
orientation = config.orientation
|
||||
darkMode = context.resources?.configuration?.uiMode?.and(Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
|
||||
|
||||
beginBenchmarkMeasure("Startup", "Godot::initEngine")
|
||||
try {
|
||||
|
|
@ -569,14 +565,19 @@ class Godot private constructor(val context: Context) {
|
|||
!isEditorHint() &&
|
||||
java.lang.Boolean.parseBoolean(GodotLib.getGlobal("display/window/per_pixel_transparency/allowed"))
|
||||
Log.d(TAG, "Render view should be transparent: $shouldBeTransparent")
|
||||
renderView = if (usesVulkan()) {
|
||||
if (meetsVulkanRequirements(context.packageManager)) {
|
||||
GodotVulkanRenderView(this, godotInputHandler, shouldBeTransparent)
|
||||
} else if (canFallbackToOpenGL()) {
|
||||
// Fallback to OpenGl.
|
||||
GodotGLRenderView(this, godotInputHandler, xrMode, useDebugOpengl, shouldBeTransparent)
|
||||
} else {
|
||||
throw IllegalStateException(context.getString(R.string.error_missing_vulkan_requirements_message))
|
||||
}
|
||||
|
||||
val nativeRenderer = getNativeRenderer();
|
||||
if (nativeRenderer == "vulkan") {
|
||||
renderView = GodotVulkanRenderView(this, godotInputHandler, shouldBeTransparent)
|
||||
} else if (nativeRenderer == "opengl3") {
|
||||
renderView = GodotGLRenderView(this, godotInputHandler, xrMode, useDebugOpengl, shouldBeTransparent)
|
||||
} else {
|
||||
throw IllegalStateException("No native renderer is available.")
|
||||
// Fallback to OpenGl.
|
||||
GodotGLRenderView(this, godotInputHandler, xrMode, useDebugOpengl, shouldBeTransparent)
|
||||
}
|
||||
|
||||
renderView?.let {
|
||||
|
|
@ -647,6 +648,9 @@ class Godot private constructor(val context: Context) {
|
|||
})
|
||||
|
||||
renderView?.queueOnRenderThread {
|
||||
for (plugin in pluginRegistry.allPlugins) {
|
||||
plugin.onRegisterPluginWithGodotNative()
|
||||
}
|
||||
setKeepScreenOn(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on")))
|
||||
}
|
||||
|
||||
|
|
@ -715,13 +719,6 @@ class Godot private constructor(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
internal fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
Log.v(TAG, "onPictureInPictureModeChanged: $isInPictureInPictureMode")
|
||||
runOnRenderThread {
|
||||
GodotLib.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||
}
|
||||
}
|
||||
|
||||
fun onPause(host: GodotHost) {
|
||||
Log.v(TAG, "OnPause: $host")
|
||||
resumed = false
|
||||
|
|
@ -778,12 +775,12 @@ class Godot private constructor(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
if (orientation != newConfig.orientation) {
|
||||
orientation = newConfig.orientation
|
||||
if (currentConfig.orientation != newConfig.orientation) {
|
||||
runOnRenderThread {
|
||||
GodotLib.onOrientationChange(orientation)
|
||||
GodotLib.onScreenRotationChange(newConfig.orientation)
|
||||
}
|
||||
}
|
||||
currentConfig = newConfig
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -847,7 +844,6 @@ class Godot private constructor(val context: Context) {
|
|||
}
|
||||
|
||||
for (plugin in pluginRegistry.allPlugins) {
|
||||
plugin.onRegisterPluginWithGodotNative()
|
||||
plugin.onGodotSetupCompleted()
|
||||
}
|
||||
primaryHost?.onGodotSetupCompleted()
|
||||
|
|
@ -936,25 +932,31 @@ class Godot private constructor(val context: Context) {
|
|||
*/
|
||||
private fun isOnUiThread() = Looper.myLooper() == Looper.getMainLooper()
|
||||
|
||||
/**
|
||||
* Returns the native rendering driver.
|
||||
/**
|
||||
* Returns true if `Vulkan` is used for rendering.
|
||||
*/
|
||||
private fun getNativeRenderer(): String {
|
||||
val rendererInfo = GodotLib.getRendererInfo(meetsVulkanRequirements(context.packageManager))
|
||||
var renderingDriverChosen = rendererInfo[0]
|
||||
var renderingDriverOriginal = rendererInfo[1]
|
||||
var renderingMethod = rendererInfo[2]
|
||||
var renderingDriverSource = rendererInfo[3]
|
||||
var renderingMethodSource = rendererInfo[4]
|
||||
Log.d(TAG, """renderingDevice: ${renderingDriverChosen} (${renderingDriverSource})
|
||||
renderer: ${renderingMethod} (${renderingMethodSource})""")
|
||||
|
||||
if (renderingDriverOriginal == "vulkan" && renderingDriverChosen == "") {
|
||||
// Throw the exception for the case where Vulkan failed to create and no fallback was available.
|
||||
throw IllegalStateException(context.getString(R.string.error_missing_vulkan_requirements_message))
|
||||
private fun usesVulkan(): Boolean {
|
||||
val rendererInfo = GodotLib.getRendererInfo()
|
||||
var renderingDeviceSource = "ProjectSettings"
|
||||
var renderingDevice = rendererInfo[0]
|
||||
var rendererSource = "ProjectSettings"
|
||||
var renderer = rendererInfo[1]
|
||||
val cmdline = commandLine
|
||||
var index = cmdline.indexOf("--rendering-method")
|
||||
if (index > -1 && cmdline.size > index + 1) {
|
||||
rendererSource = "CommandLine"
|
||||
renderer = cmdline.get(index + 1)
|
||||
}
|
||||
|
||||
return renderingDriverChosen;
|
||||
index = cmdline.indexOf("--rendering-driver")
|
||||
if (index > -1 && cmdline.size > index + 1) {
|
||||
renderingDeviceSource = "CommandLine"
|
||||
renderingDevice = cmdline.get(index + 1)
|
||||
}
|
||||
val result = ("forward_plus" == renderer || "mobile" == renderer) && "vulkan" == renderingDevice
|
||||
Log.d(TAG, """usesVulkan(): ${result}
|
||||
renderingDevice: ${renderingDevice} (${renderingDeviceSource})
|
||||
renderer: ${renderer} (${rendererSource})""")
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -976,8 +978,8 @@ class Godot private constructor(val context: Context) {
|
|||
Log.w(TAG, "The vulkan hardware level does not meet the minimum requirement: 1")
|
||||
}
|
||||
|
||||
// Check for api version 1.1
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x401000)
|
||||
// Check for api version 1.0
|
||||
return packageManager.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x400003)
|
||||
}
|
||||
|
||||
private fun setKeepScreenOn(enabled: Boolean) {
|
||||
|
|
@ -1315,11 +1317,6 @@ class Godot private constructor(val context: Context) {
|
|||
primaryHost?.onEditorWorkspaceSelected(workspace)
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeOnDistractionFreeModeChanged(enabled: Boolean) {
|
||||
primaryHost?.onDistractionFreeModeChanged(enabled)
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeBuildEnvConnect(callback: GodotCallable): Boolean {
|
||||
try {
|
||||
|
|
@ -1379,52 +1376,4 @@ class Godot private constructor(val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeIsPiPModeSupported(): Boolean {
|
||||
val hostActivity = getActivity()
|
||||
if (hostActivity is PictureInPictureProvider) {
|
||||
return hostActivity.isPiPModeSupported()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeIsInPiPMode(): Boolean {
|
||||
val hostActivity = getActivity()
|
||||
if (hostActivity is GodotActivity) {
|
||||
return hostActivity.isInPictureInPictureMode
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeEnterPiPMode() {
|
||||
val hostActivity = getActivity()
|
||||
if (hostActivity is PictureInPictureProvider) {
|
||||
runOnHostThread {
|
||||
hostActivity.enterPiPMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeSetPiPModeAspectRatio(numerator: Int, denominator: Int) {
|
||||
val hostActivity = getActivity()
|
||||
if (hostActivity is GodotActivity) {
|
||||
runOnHostThread {
|
||||
hostActivity.updatePiPParams(aspectRatio = Rational(numerator, denominator))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Keep
|
||||
private fun nativeSetAutoEnterPiPModeOnBackground(autoEnterPiPOnBackground: Boolean) {
|
||||
val hostActivity = getActivity()
|
||||
if (hostActivity is GodotActivity) {
|
||||
runOnHostThread {
|
||||
hostActivity.updatePiPParams(enableAutoEnter = autoEnterPiPOnBackground)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,25 +31,17 @@
|
|||
package org.godotengine.godot
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.PictureInPictureParams
|
||||
import android.content.ComponentName
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.Rect
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.util.Rational
|
||||
import android.view.View
|
||||
import androidx.annotation.CallSuper
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import org.godotengine.godot.feature.PictureInPictureProvider
|
||||
import org.godotengine.godot.utils.CommandLineFileParser
|
||||
import org.godotengine.godot.utils.PermissionsUtil
|
||||
import org.godotengine.godot.utils.ProcessPhoenix
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
/**
|
||||
* Base abstract activity for Android apps intending to use Godot as the primary screen.
|
||||
|
|
@ -57,7 +49,7 @@ import java.util.concurrent.atomic.AtomicReference
|
|||
* Also a reference implementation for how to setup and use the [GodotFragment] fragment
|
||||
* within an Android app.
|
||||
*/
|
||||
abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPictureProvider {
|
||||
abstract class GodotActivity : FragmentActivity(), GodotHost {
|
||||
|
||||
companion object {
|
||||
private val TAG = GodotActivity::class.java.simpleName
|
||||
|
|
@ -73,12 +65,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
private final val DEFAULT_WINDOW_ID = 664;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to true if the activity should automatically enter picture-in-picture when put in the background.
|
||||
*/
|
||||
private val pipAspectRatio = AtomicReference<Rational>()
|
||||
private val autoEnterPiP = AtomicBoolean(false)
|
||||
private val gameViewSourceRectHint = Rect()
|
||||
private val commandLineParams = ArrayList<String>()
|
||||
/**
|
||||
* Interaction with the [Godot] object is delegated to the [GodotFragment] class.
|
||||
|
|
@ -153,13 +139,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
.setPrimaryNavigationFragment(godotFragment)
|
||||
.commitNowAllowingStateLoss()
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val gameView = findViewById<View>(R.id.godot_fragment_container)
|
||||
gameView?.addOnLayoutChangeListener { v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom ->
|
||||
gameView.getGlobalVisibleRect(gameViewSourceRectHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewGodotInstanceRequested(args: Array<String>): Int {
|
||||
|
|
@ -170,7 +149,7 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
.putExtra(EXTRA_COMMAND_LINE_PARAMS, args)
|
||||
triggerRebirth(null, intent)
|
||||
// fake 'process' id returned by create_instance() etc
|
||||
return DEFAULT_WINDOW_ID
|
||||
return DEFAULT_WINDOW_ID;
|
||||
}
|
||||
|
||||
protected fun triggerRebirth(bundle: Bundle?, intent: Intent) {
|
||||
|
|
@ -188,15 +167,6 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
|
||||
if (isInPictureInPictureMode && !isFinishing) {
|
||||
// We get in this state when PiP is closed, so we terminate the activity.
|
||||
finish()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onGodotForceQuit(instance: Godot) {
|
||||
runOnUiThread { terminateGodotInstance(instance) }
|
||||
}
|
||||
|
|
@ -226,31 +196,13 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
}
|
||||
}
|
||||
|
||||
override fun onGodotSetupCompleted() {
|
||||
super.onGodotSetupCompleted()
|
||||
|
||||
if (isPiPEnabled()) {
|
||||
try {
|
||||
// Update the aspect ratio for picture-in-picture mode.
|
||||
val viewportWidth = Integer.parseInt(GodotLib.getGlobal("display/window/size/viewport_width"))
|
||||
val viewportHeight = Integer.parseInt(GodotLib.getGlobal("display/window/size/viewport_height"))
|
||||
pipAspectRatio.set(Rational(viewportWidth, viewportHeight))
|
||||
} catch (e: NumberFormatException) {
|
||||
Log.w(TAG, "Unable to parse viewport dimensions.", e)
|
||||
}
|
||||
|
||||
runOnHostThread { updatePiPParams() }
|
||||
}
|
||||
}
|
||||
|
||||
override fun onNewIntent(newIntent: Intent) {
|
||||
intent = sanitizeLaunchIntent(newIntent)
|
||||
super.onNewIntent(intent)
|
||||
handleStartIntent(intent, false)
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected open fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
|
||||
private fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
|
||||
if (!newLaunch) {
|
||||
val newLaunchRequested = intent.getBooleanExtra(EXTRA_NEW_LAUNCH, false)
|
||||
if (newLaunchRequested) {
|
||||
|
|
@ -304,56 +256,4 @@ abstract class GodotActivity : FragmentActivity(), GodotHost, PictureInPicturePr
|
|||
|
||||
@CallSuper
|
||||
override fun getCommandLine(): MutableList<String> = commandLineParams
|
||||
|
||||
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
|
||||
super.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||
godot?.onPictureInPictureModeChanged(isInPictureInPictureMode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if picture-in-picture (PiP) mode is supported.
|
||||
*/
|
||||
override fun isPiPModeSupported() = isPiPEnabled() && packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
|
||||
|
||||
/**
|
||||
* Returns true if the current activity has enabled picture-in-picture in its manifest declaration using
|
||||
* 'android:supportsPictureInPicture="true"'
|
||||
*/
|
||||
protected open fun isPiPEnabled() = false
|
||||
|
||||
internal fun updatePiPParams(enableAutoEnter: Boolean = autoEnterPiP.get(), aspectRatio: Rational? = pipAspectRatio.get()) {
|
||||
if (isPiPModeSupported()) {
|
||||
autoEnterPiP.set(enableAutoEnter)
|
||||
pipAspectRatio.set(aspectRatio)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
val builder = PictureInPictureParams.Builder()
|
||||
.setSourceRectHint(gameViewSourceRectHint)
|
||||
.setAspectRatio(aspectRatio)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
builder.setSeamlessResizeEnabled(false)
|
||||
.setAutoEnterEnabled(enableAutoEnter)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
builder.setExpandedAspectRatio(aspectRatio)
|
||||
}
|
||||
setPictureInPictureParams(builder.build())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun enterPiPMode() {
|
||||
if (isPiPModeSupported()) {
|
||||
updatePiPParams()
|
||||
|
||||
Log.v(TAG, "Entering PiP mode")
|
||||
enterPictureInPictureMode()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onUserLeaveHint() {
|
||||
if (autoEnterPiP.get()) {
|
||||
enterPiPMode()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,13 +496,6 @@ public class GodotFragment extends Fragment implements IDownloaderClient, GodotH
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDistractionFreeModeChanged(Boolean enabled) {
|
||||
if (parentHost != null) {
|
||||
parentHost.onDistractionFreeModeChanged(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BuildProvider getBuildProvider() {
|
||||
if (parentHost != null) {
|
||||
|
|
|
|||
|
|
@ -153,11 +153,6 @@ public interface GodotHost {
|
|||
*/
|
||||
default void onEditorWorkspaceSelected(String workspace) {}
|
||||
|
||||
/**
|
||||
* Triggered when the editor's distraction-free mode changes.
|
||||
*/
|
||||
default void onDistractionFreeModeChanged(Boolean enabled) {}
|
||||
|
||||
/**
|
||||
* Runs the specified action on a host provided thread.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -192,14 +192,11 @@ public class GodotLib {
|
|||
/**
|
||||
* Used to get info about the current rendering system.
|
||||
*
|
||||
* @return A String array with three elements:
|
||||
* [0] Rendering driver name chosen for rendering.
|
||||
* [1] Rendering driver name chosen before any fallbacks were applied.
|
||||
* [2] Rendering method.
|
||||
* [3] Source where the rendering driver was chosen from.
|
||||
* [4] Source where the rendering method was chosen from.
|
||||
* @return A String array with two elements:
|
||||
* [0] Rendering driver name.
|
||||
* [1] Rendering method.
|
||||
*/
|
||||
public static native String[] getRendererInfo(boolean p_vulkan_requirements_met);
|
||||
public static native String[] getRendererInfo();
|
||||
|
||||
/**
|
||||
* Used to access Godot's editor settings.
|
||||
|
|
@ -302,7 +299,7 @@ public class GodotLib {
|
|||
* Invoked when the screen orientation changes.
|
||||
* @param orientation the new screen orientation
|
||||
*/
|
||||
static native void onOrientationChange(int orientation);
|
||||
static native void onScreenRotationChange(int orientation);
|
||||
|
||||
/**
|
||||
* @return true if input must be dispatched from the render thread. If false, input is
|
||||
|
|
@ -320,6 +317,4 @@ public class GodotLib {
|
|||
static native boolean isProjectManagerHint();
|
||||
|
||||
static native boolean hasFeature(String feature);
|
||||
|
||||
static native void onPictureInPictureModeChanged(boolean isInPictureInPictureMode);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,4 @@ package org.godotengine.godot.editor.utils
|
|||
object EditorUtils {
|
||||
@JvmStatic
|
||||
external fun runScene(scene: String, sceneArgs: Array<String>)
|
||||
|
||||
@JvmStatic
|
||||
external fun toggleTitleBar(visible: Boolean)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,41 +0,0 @@
|
|||
/**************************************************************************/
|
||||
/* PictureInPictureProvider.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.godot.feature
|
||||
|
||||
/**
|
||||
* Provides APIs to enable picture-in-picture.
|
||||
*/
|
||||
interface PictureInPictureProvider {
|
||||
|
||||
fun enterPiPMode()
|
||||
|
||||
fun isPiPModeSupported(): Boolean
|
||||
}
|
||||
|
|
@ -57,7 +57,7 @@ public class GodotEditText extends EditText {
|
|||
private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
|
||||
private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
|
||||
|
||||
// Enum must be kept up-to-date with DisplayServerEnums::VirtualKeyboardType
|
||||
// Enum must be kept up-to-date with DisplayServer::VirtualKeyboardType
|
||||
public enum VirtualKeyboardType {
|
||||
KEYBOARD_TYPE_DEFAULT,
|
||||
KEYBOARD_TYPE_MULTILINE,
|
||||
|
|
|
|||
|
|
@ -57,11 +57,6 @@ internal class GodotGestureHandler(private val inputHandler: GodotInputHandler)
|
|||
|
||||
var scrollDeadzoneDisabled = false
|
||||
|
||||
/**
|
||||
* Enable haptic feedback on long-press right-click
|
||||
*/
|
||||
var hapticFeedbackEnabled = false
|
||||
|
||||
private var nextDownIsDoubleTap = false
|
||||
private var dragInProgress = false
|
||||
private var scaleInProgress = false
|
||||
|
|
@ -85,9 +80,6 @@ internal class GodotGestureHandler(private val inputHandler: GodotInputHandler)
|
|||
override fun onLongPress(event: MotionEvent) {
|
||||
val toolType = GodotInputHandler.getEventToolType(event)
|
||||
if (toolType != MotionEvent.TOOL_TYPE_MOUSE) {
|
||||
if (hapticFeedbackEnabled) {
|
||||
inputHandler.performHapticFeedback()
|
||||
}
|
||||
contextClickRouter(event)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ import android.util.Log;
|
|||
import android.util.SparseArray;
|
||||
import android.util.SparseIntArray;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.HapticFeedbackConstants;
|
||||
import android.view.InputDevice;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
|
|
@ -134,23 +133,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener, Sens
|
|||
this.godotGestureHandler.setScrollDeadzoneDisabled(disable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable haptic feedback (vibration) when a long-press right-click is triggered.
|
||||
*/
|
||||
public void enableHapticFeedback(boolean enable) {
|
||||
this.godotGestureHandler.setHapticFeedbackEnabled(enable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform haptic feedback on the render view.
|
||||
*/
|
||||
void performHapticFeedback() {
|
||||
GodotRenderView view = godot.getRenderView();
|
||||
if (view != null) {
|
||||
view.getView().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable multi-fingers pan & scale gestures. This is false by default.
|
||||
* <p>
|
||||
|
|
|
|||
|
|
@ -203,10 +203,8 @@ internal abstract class DataAccess {
|
|||
abstract fun write(buffer: ByteBuffer): Boolean
|
||||
|
||||
fun seekFromEnd(positionFromEnd: Long) {
|
||||
val positionFromBeginning = size() + positionFromEnd
|
||||
if (positionFromBeginning >= 0) {
|
||||
seek(positionFromBeginning)
|
||||
}
|
||||
val positionFromBeginning = max(0, size() - positionFromEnd)
|
||||
seek(positionFromBeginning)
|
||||
}
|
||||
|
||||
abstract class FileChannelDataAccess(private val filePath: String) : DataAccess() {
|
||||
|
|
|
|||
|
|
@ -32,13 +32,10 @@ package org.godotengine.godot.plugin
|
|||
|
||||
import android.content.Intent
|
||||
import android.util.Log
|
||||
import androidx.annotation.Keep
|
||||
import androidx.core.net.toUri
|
||||
|
||||
import org.godotengine.godot.Godot
|
||||
import org.godotengine.godot.variant.Callable
|
||||
import java.lang.reflect.InvocationHandler
|
||||
import java.lang.reflect.Proxy
|
||||
|
||||
/**
|
||||
* Built-in Godot Android plugin used to provide access to the Android runtime capabilities.
|
||||
|
|
@ -46,76 +43,7 @@ import java.lang.reflect.Proxy
|
|||
* @see <a href="https://docs.godotengine.org/en/latest/tutorials/platform/android/javaclasswrapper_and_androidruntimeplugin.html">Integrating with Android APIs</a>
|
||||
*/
|
||||
class AndroidRuntimePlugin(godot: Godot) : GodotPlugin(godot) {
|
||||
|
||||
companion object {
|
||||
private val TAG = AndroidRuntimePlugin::class.java.simpleName
|
||||
|
||||
/**
|
||||
* Helper method used to generate Godot Proxy instances.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Keep
|
||||
private fun generateProxyInstance(interfaces: Array<String>, invocationHandler: InvocationHandler): Any? {
|
||||
try {
|
||||
val interfaceClasses = interfaces.map { Class.forName(it) }.toTypedArray()
|
||||
|
||||
val proxy = Proxy.newProxyInstance(invocationHandler.javaClass.classLoader, interfaceClasses, invocationHandler)
|
||||
return proxy
|
||||
} catch (e: Exception) {
|
||||
Log.w(TAG, "Error generating Godot proxy for interfaces ${interfaces.joinToString(",")}", e)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to create [java.lang.reflect.Proxy] instance wrapping a given Godot [Callable].
|
||||
*
|
||||
* The [Proxy] instance is used to implement one SAM interface with the [Callable] serving as the delegate
|
||||
* implementation for the SAM interface overridden methods.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Keep
|
||||
private fun createProxyFromGodotCallable(interfaceName: String, godotCallable: Callable): Any? {
|
||||
return generateProxyInstance(arrayOf(interfaceName)) { proxy, method, args ->
|
||||
when (method.name) {
|
||||
// We automatically handle 'toString', 'equals' and 'hashCode' to simplify the task of the caller
|
||||
// and provide consistency.
|
||||
"toString" -> "Godot Callable Proxy for $interfaceName"
|
||||
"equals" -> proxy == args[0]
|
||||
"hashCode" -> godotCallable.hashCode()
|
||||
|
||||
// Invocation for the interface single abstract method falls here and is dispatched to the
|
||||
// Godot [Callable].
|
||||
else -> godotCallable.call(*args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method used to create [java.lang.reflect.Proxy] instance wrapping a given Godot Object represented by
|
||||
* its ObjectID.
|
||||
*
|
||||
* The [Proxy] instance is used to implement one or multiple interfaces with the Object represented by
|
||||
* [godotObjectID] serving as the delegate implementation for the interface(s) overridden methods.
|
||||
*/
|
||||
@JvmStatic
|
||||
@Keep
|
||||
private fun createProxyFromGodotObjectID(godotObjectID: Long, interfaces: Array<String>): Any? {
|
||||
return generateProxyInstance(interfaces) { proxy, method, args ->
|
||||
when (val methodName = method.name) {
|
||||
// We automatically handle 'toString', 'equals' and 'hashCode' to simplify the task of the caller
|
||||
// and provide consistency.
|
||||
"toString" -> "Godot Object Proxy for ${interfaces.joinToString(",")}"
|
||||
"equals" -> proxy == args[0]
|
||||
"hashCode" -> godotObjectID
|
||||
|
||||
// Invocation for the remaining interface(s) methods falls here and is dispatched to the
|
||||
// Godot Object.
|
||||
else -> Callable.call(godotObjectID, methodName, *args)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private val TAG = AndroidRuntimePlugin::class.java.simpleName
|
||||
|
||||
override fun getPluginName() = "AndroidRuntime"
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ import java.util.Set;
|
|||
*/
|
||||
@Keep
|
||||
public class GodotTTS extends UtteranceProgressListener implements TextToSpeech.OnInitListener {
|
||||
// Note: These constants must be in sync with DisplayServerEnums::TTSUtteranceEvent enum from "servers/display/display_server.h".
|
||||
// Note: These constants must be in sync with DisplayServer::TTSUtteranceEvent enum from "servers/display/display_server.h".
|
||||
final private static int EVENT_START = 0;
|
||||
final private static int EVENT_END = 1;
|
||||
final private static int EVENT_CANCEL = 2;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ private val benchmarkTracker = Collections.synchronizedMap(LinkedHashMap<Pair<St
|
|||
* Note: Only enabled on 'editorDev' build variant.
|
||||
*/
|
||||
fun beginBenchmarkMeasure(scope: String, label: String) {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "debug") {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "dev") {
|
||||
return
|
||||
}
|
||||
val key = Pair(scope, label)
|
||||
|
|
@ -84,7 +84,7 @@ fun beginBenchmarkMeasure(scope: String, label: String) {
|
|||
*/
|
||||
@JvmOverloads
|
||||
fun endBenchmarkMeasure(scope: String, label: String, dumpBenchmark: Boolean = false) {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "debug") {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "dev") {
|
||||
return
|
||||
}
|
||||
val key = Pair(scope, label)
|
||||
|
|
@ -109,7 +109,7 @@ fun endBenchmarkMeasure(scope: String, label: String, dumpBenchmark: Boolean = f
|
|||
*/
|
||||
@JvmOverloads
|
||||
fun dumpBenchmark(fileAccessHandler: FileAccessHandler? = null, filepath: String? = benchmarkFile) {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "debug") {
|
||||
if (BuildConfig.FLAVOR != "editor" || BuildConfig.BUILD_TYPE != "dev") {
|
||||
return
|
||||
}
|
||||
if (!useBenchmark || benchmarkTracker.isEmpty()) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue