diff options
Diffstat (limited to 'platform/android/java/editor')
8 files changed, 448 insertions, 0 deletions
diff --git a/platform/android/java/editor/build.gradle b/platform/android/java/editor/build.gradle new file mode 100644 index 0000000000..729966ee69 --- /dev/null +++ b/platform/android/java/editor/build.gradle @@ -0,0 +1,82 @@ +// Gradle build config for Godot Engine's Android port. +plugins { +    id 'com.android.application' +    id 'org.jetbrains.kotlin.android' +} + +dependencies { +    implementation libraries.kotlinStdLib +    implementation libraries.androidxFragment +    implementation project(":lib") + +    implementation "androidx.window:window:1.0.0" +} + +android { +    compileSdkVersion versions.compileSdk +    buildToolsVersion versions.buildTools +    ndkVersion versions.ndkVersion + +    defaultConfig { +        // The 'applicationId' suffix allows to install Godot 3.x(v3) and 4.x(v4) on the same device +        applicationId "org.godotengine.editor.v4" +        versionCode getGodotLibraryVersionCode() +        versionName getGodotLibraryVersionName() +        minSdkVersion versions.minSdk +        targetSdkVersion versions.targetSdk + +        missingDimensionStrategy 'products', 'editor' +    } + +    compileOptions { +        sourceCompatibility versions.javaVersion +        targetCompatibility versions.javaVersion +    } + +    kotlinOptions { +        jvmTarget = versions.javaVersion +    } + +    buildTypes { +        dev { +            initWith debug +            applicationIdSuffix ".dev" +        } + +        debug { +            initWith release + +            // Need to swap with the release signing config when this is ready for public release. +            signingConfig signingConfigs.debug +        } + +        release { +            // This buildtype is disabled below. +            // The editor can't be used with target=release only, as debugging tools are then not +            // included, and it would crash on errors instead of reporting them. +        } +    } + +    packagingOptions { +        // 'doNotStrip' is enabled for development within Android Studio +        if (shouldNotStrip()) { +            doNotStrip '**/*.so' +        } +    } + +    // Disable 'release' buildtype. +    // The editor can't be used with target=release only, as debugging tools are then not +    // included, and it would crash on errors instead of reporting them. +    variantFilter { variant -> +        if (variant.buildType.name == "release") { +            setIgnore(true) +        } +    } + +    applicationVariants.all { variant -> +        variant.outputs.all { output -> +            def suffix = variant.name == "dev" ? "_dev" : "" +            output.outputFileName = "android_editor${suffix}.apk" +        } +    } +} diff --git a/platform/android/java/editor/src/dev/res/values/strings.xml b/platform/android/java/editor/src/dev/res/values/strings.xml new file mode 100644 index 0000000000..45fae3fd39 --- /dev/null +++ b/platform/android/java/editor/src/dev/res/values/strings.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> +	<string name="godot_editor_name_string">Godot Editor 4.x (dev)</string> +</resources> diff --git a/platform/android/java/editor/src/main/AndroidManifest.xml b/platform/android/java/editor/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..abf506a83c --- /dev/null +++ b/platform/android/java/editor/src/main/AndroidManifest.xml @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" +    xmlns:tools="http://schemas.android.com/tools" +    package="org.godotengine.editor" +    android:installLocation="auto"> + +    <supports-screens +        android:largeScreens="true" +        android:normalScreens="true" +        android:smallScreens="true" +        android:xlargeScreens="true" /> + +    <uses-feature +        android:glEsVersion="0x00020000" +        android:required="true" /> + +    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" +        tools:ignore="ScopedStorage" /> +    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" +        android:maxSdkVersion="29"/> +    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" +        android:maxSdkVersion="29"/> +    <uses-permission android:name="android.permission.INTERNET" /> + +    <application +        android:allowBackup="false" +        android:icon="@mipmap/icon" +        android:label="@string/godot_editor_name_string" +        tools:ignore="GoogleAppIndexingWarning" +        android:requestLegacyExternalStorage="true"> + +        <activity +            android:name=".GodotProjectManager" +            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode" +            android:launchMode="singleTask" +            android:screenOrientation="userLandscape" +            android:exported="true" +            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen" +            android:process=":GodotProjectManager"> + +            <layout android:defaultHeight="@dimen/editor_default_window_height" +                android:defaultWidth="@dimen/editor_default_window_width" /> + +            <intent-filter> +                <action android:name="android.intent.action.MAIN" /> +                <category android:name="android.intent.category.LAUNCHER" /> +            </intent-filter> +        </activity> + +        <activity +            android:name=".GodotEditor" +            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode" +            android:process=":GodotEditor" +            android:launchMode="singleTask" +            android:screenOrientation="userLandscape" +            android:exported="false" +            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> +            <layout android:defaultHeight="@dimen/editor_default_window_height" +                android:defaultWidth="@dimen/editor_default_window_width" /> +        </activity> + +        <activity +            android:name=".GodotGame" +            android:configChanges="orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode" +            android:label="@string/godot_project_name_string" +            android:process=":GodotGame" +            android:launchMode="singleTask" +            android:exported="false" +            android:screenOrientation="userLandscape" +            android:theme="@android:style/Theme.Black.NoTitleBar.Fullscreen"> +            <layout android:defaultHeight="@dimen/editor_default_window_height" +                android:defaultWidth="@dimen/editor_default_window_width" /> +        </activity> + +    </application> + +</manifest> diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt new file mode 100644 index 0000000000..740f3f48d3 --- /dev/null +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -0,0 +1,196 @@ +/*************************************************************************/ +/*  GodotEditor.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 android.Manifest +import android.content.Intent +import android.content.pm.PackageManager +import android.os.Build +import android.os.Bundle +import android.os.Debug +import android.os.Environment +import android.widget.Toast +import androidx.window.layout.WindowMetricsCalculator +import org.godotengine.godot.FullScreenGodotApp +import org.godotengine.godot.utils.PermissionsUtil +import java.util.* +import kotlin.math.min + +/** + * Base class for the Godot Android Editor activities. + * + * 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 : FullScreenGodotApp() { + +	companion object { +		private const val WAIT_FOR_DEBUGGER = false + +		private const val COMMAND_LINE_PARAMS = "command_line_params" + +		private const val EDITOR_ARG = "--editor" +		private const val PROJECT_MANAGER_ARG = "--project-manager" +	} + +	private val commandLineParams = ArrayList<String>() + +	override fun onCreate(savedInstanceState: Bundle?) { +		PermissionsUtil.requestManifestPermissions(this) + +		val params = intent.getStringArrayExtra(COMMAND_LINE_PARAMS) +		updateCommandLineParams(params) + +		if (BuildConfig.BUILD_TYPE == "dev" && WAIT_FOR_DEBUGGER) { +			Debug.waitForDebugger() +		} + +		super.onCreate(savedInstanceState) +	} + +	private fun updateCommandLineParams(args: Array<String>?) { +		// Update the list of command line params with the new args +		commandLineParams.clear() +		if (args != null && args.isNotEmpty()) { +			commandLineParams.addAll(listOf(*args)) +		} +	} + +	override fun getCommandLine() = commandLineParams + +	override fun onNewGodotInstanceRequested(args: Array<String>) { +		// Parse the arguments to figure out which activity to start. +		var targetClass: Class<*> = GodotGame::class.java + +		// Whether we should launch the new godot instance in an adjacent window +		// https://developer.android.com/reference/android/content/Intent#FLAG_ACTIVITY_LAUNCH_ADJACENT +		var launchAdjacent = +			Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && (isInMultiWindowMode || isLargeScreen) + +		for (arg in args) { +			if (EDITOR_ARG == arg) { +				targetClass = GodotEditor::class.java +				launchAdjacent = false +				break +			} + +			if (PROJECT_MANAGER_ARG == arg) { +				targetClass = GodotProjectManager::class.java +				launchAdjacent = false +				break +			} +		} + +		// Launch a new activity +		val newInstance = Intent(this, targetClass) +			.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) +			.putExtra(COMMAND_LINE_PARAMS, args) +		if (launchAdjacent) { +			newInstance.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT) +		} +		startActivity(newInstance) +	} + +	// Get the screen's density scale +	protected val isLargeScreen: Boolean +		// Get the minimum window size // Correspond to the EXPANDED window size class. +		get() { +			val metrics = WindowMetricsCalculator.getOrCreate().computeMaximumWindowMetrics(this) + +			// Get the screen's density scale +			val scale = resources.displayMetrics.density + +			// Get the minimum window size +			val minSize = min(metrics.bounds.width(), metrics.bounds.height()).toFloat() +			val minSizeDp = minSize / scale +			return minSizeDp >= 840f // Correspond to the EXPANDED window size class. +		} + +	override fun setRequestedOrientation(requestedOrientation: Int) { +		if (!overrideOrientationRequest()) { +			super.setRequestedOrientation(requestedOrientation) +		} +	} + +	/** +	 * The Godot Android Editor sets its own orientation via its AndroidManifest +	 */ +	protected open fun overrideOrientationRequest() = true + +	override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { +		super.onActivityResult(requestCode, resultCode, data) +		// Check if we got the MANAGE_EXTERNAL_STORAGE permission +		if (requestCode == PermissionsUtil.REQUEST_MANAGE_EXTERNAL_STORAGE_REQ_CODE) { +			if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { +				if (!Environment.isExternalStorageManager()) { +					Toast.makeText( +						this, +						R.string.denied_storage_permission_error_msg, +						Toast.LENGTH_LONG +					).show() +				} +			} +		} +	} + +	override fun onRequestPermissionsResult( +		requestCode: Int, +		permissions: Array<String?>, +		grantResults: IntArray +	) { +		super.onRequestPermissionsResult(requestCode, permissions, grantResults) +		// Check if we got access to the necessary storage permissions +		if (requestCode == PermissionsUtil.REQUEST_ALL_PERMISSION_REQ_CODE) { +			if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { +				var hasReadAccess = false +				var hasWriteAccess = false +				for (i in permissions.indices) { +					if (Manifest.permission.READ_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) { +						hasReadAccess = true +					} +					if (Manifest.permission.WRITE_EXTERNAL_STORAGE == permissions[i] && grantResults[i] == PackageManager.PERMISSION_GRANTED) { +						hasWriteAccess = true +					} +				} +				if (!hasReadAccess || !hasWriteAccess) { +					Toast.makeText( +						this, +						R.string.denied_storage_permission_error_msg, +						Toast.LENGTH_LONG +					).show() +				} +			} +		} +	} +} diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt new file mode 100644 index 0000000000..783095f93a --- /dev/null +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotGame.kt @@ -0,0 +1,38 @@ +/*************************************************************************/ +/*  GodotGame.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 + +/** + * Drives the 'run project' window of the Godot Editor. + */ +class GodotGame : GodotEditor() { +	override fun overrideOrientationRequest() = false +} diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt new file mode 100644 index 0000000000..bcf4659603 --- /dev/null +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotProjectManager.kt @@ -0,0 +1,40 @@ +/*************************************************************************/ +/*  GodotProjectManager.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 + +/** + * Launcher activity for the Godot Android Editor. + * + * It presents the user with the project manager interface. + * Upon selection of a project, this activity (via its parent logic) starts the + * [GodotEditor] activity. + */ +class GodotProjectManager : GodotEditor() diff --git a/platform/android/java/editor/src/main/res/values/dimens.xml b/platform/android/java/editor/src/main/res/values/dimens.xml new file mode 100644 index 0000000000..03fb6184d2 --- /dev/null +++ b/platform/android/java/editor/src/main/res/values/dimens.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> +	<dimen name="editor_default_window_height">600dp</dimen> +	<dimen name="editor_default_window_width">800dp</dimen> +</resources> diff --git a/platform/android/java/editor/src/main/res/values/strings.xml b/platform/android/java/editor/src/main/res/values/strings.xml new file mode 100644 index 0000000000..837a5d62e1 --- /dev/null +++ b/platform/android/java/editor/src/main/res/values/strings.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> +	<string name="godot_editor_name_string">Godot Editor 4.x</string> + +	<string name="denied_storage_permission_error_msg">Missing storage access permission!</string> +</resources>  |