You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-21 14:57:09 +00:00
Make use of activity-alias as the launcher mechanism for the Godot editor and the Godot app template
This commit is contained in:
@@ -2561,7 +2561,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
|
|||||||
print_verbose(output);
|
print_verbose(output);
|
||||||
if (err || rv != 0 || output.contains("Error: Activity not started")) {
|
if (err || rv != 0 || output.contains("Error: Activity not started")) {
|
||||||
// The implicit launch failed, let's try an explicit launch by specifying the component name before giving up.
|
// The implicit launch failed, let's try an explicit launch by specifying the component name before giving up.
|
||||||
const String component_name = get_package_name(p_preset, package_name) + "/com.godot.game.GodotApp";
|
const String component_name = get_package_name(p_preset, package_name) + "/com.godot.game.GodotAppLauncher";
|
||||||
print_line("Implicit launch failed... Trying explicit launch using", component_name);
|
print_line("Implicit launch failed... Trying explicit launch using", component_name);
|
||||||
args.erase(get_package_name(p_preset, package_name));
|
args.erase(get_package_name(p_preset, package_name));
|
||||||
args.push_back("-n");
|
args.push_back("-n");
|
||||||
|
|||||||
@@ -31,6 +31,7 @@
|
|||||||
#include "gradle_export_util.h"
|
#include "gradle_export_util.h"
|
||||||
|
|
||||||
#include "core/string/translation_server.h"
|
#include "core/string/translation_server.h"
|
||||||
|
#include "modules/regex/regex.h"
|
||||||
|
|
||||||
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
|
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
|
||||||
switch (screen_orientation) {
|
switch (screen_orientation) {
|
||||||
@@ -284,6 +285,19 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug) {
|
String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug) {
|
||||||
|
String export_plugins_activity_element_contents;
|
||||||
|
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
||||||
|
for (int i = 0; i < export_plugins.size(); i++) {
|
||||||
|
if (export_plugins[i]->supports_platform(p_export_platform)) {
|
||||||
|
const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
|
||||||
|
if (!contents.is_empty()) {
|
||||||
|
export_plugins_activity_element_contents += contents;
|
||||||
|
export_plugins_activity_element_contents += "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the GodotApp activity tag.
|
||||||
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(p_export_platform->get_project_setting(p_preset, "display/window/handheld/orientation"))));
|
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(p_export_platform->get_project_setting(p_preset, "display/window/handheld/orientation"))));
|
||||||
String manifest_activity_text = vformat(
|
String manifest_activity_text = vformat(
|
||||||
" <activity android:name=\".GodotApp\" "
|
" <activity android:name=\".GodotApp\" "
|
||||||
@@ -296,6 +310,20 @@ String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, con
|
|||||||
orientation,
|
orientation,
|
||||||
bool_to_string(bool(p_export_platform->get_project_setting(p_preset, "display/window/size/resizable"))));
|
bool_to_string(bool(p_export_platform->get_project_setting(p_preset, "display/window/size/resizable"))));
|
||||||
|
|
||||||
|
// *LAUNCHER and *HOME categories should only go to the activity-alias.
|
||||||
|
Ref<RegEx> activity_content_to_remove_regex = RegEx::create_from_string(R"delim(<category\s+android:name\s*=\s*"\S+(LAUNCHER|HOME)"\s*\/>)delim");
|
||||||
|
String updated_export_plugins_activity_element_contents = activity_content_to_remove_regex->sub(export_plugins_activity_element_contents, "", true);
|
||||||
|
manifest_activity_text += updated_export_plugins_activity_element_contents;
|
||||||
|
|
||||||
|
manifest_activity_text += " </activity>\n";
|
||||||
|
|
||||||
|
// Update the GodotAppLauncher activity tag.
|
||||||
|
manifest_activity_text += " <activity-alias\n"
|
||||||
|
" tools:node=\"mergeOnlyAttributes\"\n"
|
||||||
|
" android:name=\".GodotAppLauncher\"\n"
|
||||||
|
" android:targetActivity=\".GodotApp\"\n"
|
||||||
|
" android:exported=\"true\">\n";
|
||||||
|
|
||||||
manifest_activity_text += " <intent-filter>\n"
|
manifest_activity_text += " <intent-filter>\n"
|
||||||
" <action android:name=\"android.intent.action.MAIN\" />\n"
|
" <action android:name=\"android.intent.action.MAIN\" />\n"
|
||||||
" <category android:name=\"android.intent.category.DEFAULT\" />\n";
|
" <category android:name=\"android.intent.category.DEFAULT\" />\n";
|
||||||
@@ -317,18 +345,12 @@ String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, con
|
|||||||
|
|
||||||
manifest_activity_text += " </intent-filter>\n";
|
manifest_activity_text += " </intent-filter>\n";
|
||||||
|
|
||||||
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
|
// Hybrid categories should only go to the actual 'GodotApp' activity.
|
||||||
for (int i = 0; i < export_plugins.size(); i++) {
|
Ref<RegEx> activity_alias_content_to_remove_regex = RegEx::create_from_string(R"delim(<category\s+android:name\s*=\s*"org.godotengine.xr.hybrid.(IMMERSIVE|PANEL)"\s*\/>)delim");
|
||||||
if (export_plugins[i]->supports_platform(p_export_platform)) {
|
String updated_export_plugins_activity_alias_element_contents = activity_alias_content_to_remove_regex->sub(export_plugins_activity_element_contents, "", true);
|
||||||
const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
|
manifest_activity_text += updated_export_plugins_activity_alias_element_contents;
|
||||||
if (!contents.is_empty()) {
|
|
||||||
manifest_activity_text += contents;
|
|
||||||
manifest_activity_text += "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
manifest_activity_text += " </activity>\n";
|
manifest_activity_text += " </activity-alias>\n";
|
||||||
return manifest_activity_text;
|
return manifest_activity_text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,9 +35,11 @@ configurations {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// Android instrumented test dependencies
|
// Android instrumented test dependencies
|
||||||
androidTestImplementation "androidx.test.ext:junit:1.3.0"
|
androidTestImplementation "androidx.test.ext:junit:$versions.junitVersion"
|
||||||
androidTestImplementation "androidx.test.espresso:espresso-core:3.7.0"
|
androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCoreVersion"
|
||||||
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:1.3.11"
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$versions.kotlinTestVersion"
|
||||||
|
androidTestImplementation "androidx.test:runner:$versions.testRunnerVersion"
|
||||||
|
androidTestUtil "androidx.test:orchestrator:$versions.testOrchestratorVersion"
|
||||||
|
|
||||||
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
implementation "androidx.fragment:fragment:$versions.fragmentVersion"
|
||||||
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
|
||||||
@@ -121,6 +123,15 @@ android {
|
|||||||
missingDimensionStrategy 'products', 'template'
|
missingDimensionStrategy 'products', 'template'
|
||||||
|
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
// The following argument makes the Android Test Orchestrator run its
|
||||||
|
// "pm clear" command after each test invocation. This command ensures
|
||||||
|
// that the app's state is completely cleared between tests.
|
||||||
|
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||||
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
execution 'ANDROIDX_TEST_ORCHESTRATOR'
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
|||||||
@@ -15,8 +15,12 @@ ext.versions = [
|
|||||||
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
|
// Also update 'platform/android/detect.py#get_ndk_version()' when this is updated.
|
||||||
ndkVersion : '28.1.13356709',
|
ndkVersion : '28.1.13356709',
|
||||||
splashscreenVersion: '1.0.1',
|
splashscreenVersion: '1.0.1',
|
||||||
openxrVendorsVersion: '4.1.1-stable'
|
openxrVendorsVersion: '4.1.1-stable',
|
||||||
|
junitVersion : '1.3.0',
|
||||||
|
espressoCoreVersion: '3.7.0',
|
||||||
|
kotlinTestVersion : '1.3.11',
|
||||||
|
testRunnerVersion : '1.7.0',
|
||||||
|
testOrchestratorVersion: '1.6.1',
|
||||||
]
|
]
|
||||||
|
|
||||||
ext.getExportPackageName = { ->
|
ext.getExportPackageName = { ->
|
||||||
|
|||||||
@@ -30,15 +30,19 @@
|
|||||||
|
|
||||||
package com.godot.game
|
package com.godot.game
|
||||||
|
|
||||||
|
import android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule
|
import androidx.test.core.app.ActivityScenario
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
import com.godot.game.test.GodotAppInstrumentedTestPlugin
|
import com.godot.game.test.GodotAppInstrumentedTestPlugin
|
||||||
|
import org.godotengine.godot.GodotActivity.Companion.EXTRA_COMMAND_LINE_PARAMS
|
||||||
import org.godotengine.godot.plugin.GodotPluginRegistry
|
import org.godotengine.godot.plugin.GodotPluginRegistry
|
||||||
import org.junit.Rule
|
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.test.assertEquals
|
||||||
import kotlin.test.assertNotNull
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
import kotlin.test.assertTrue
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,28 +53,94 @@ class GodotAppTest {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val TAG = GodotAppTest::class.java.simpleName
|
private val TAG = GodotAppTest::class.java.simpleName
|
||||||
}
|
|
||||||
|
|
||||||
@get:Rule
|
private const val GODOT_APP_LAUNCHER_CLASS_NAME = "com.godot.game.GodotAppLauncher"
|
||||||
val godotAppRule = ActivityScenarioRule(GodotApp::class.java)
|
private const val GODOT_APP_CLASS_NAME = "com.godot.game.GodotApp"
|
||||||
|
|
||||||
|
private val TEST_COMMAND_LINE_PARAMS = arrayOf("This is a test")
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs the JavaClassWrapper tests via the GodotAppInstrumentedTestPlugin.
|
* Runs the JavaClassWrapper tests via the GodotAppInstrumentedTestPlugin.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun runJavaClassWrapperTests() {
|
fun runJavaClassWrapperTests() {
|
||||||
val testPlugin = GodotPluginRegistry.getPluginRegistry()
|
ActivityScenario.launch(GodotApp::class.java).use { scenario ->
|
||||||
.getPlugin("GodotAppInstrumentedTestPlugin") as GodotAppInstrumentedTestPlugin?
|
scenario.onActivity { activity ->
|
||||||
assertNotNull(testPlugin)
|
val testPlugin = GodotPluginRegistry.getPluginRegistry()
|
||||||
|
.getPlugin("GodotAppInstrumentedTestPlugin") as GodotAppInstrumentedTestPlugin?
|
||||||
|
assertNotNull(testPlugin)
|
||||||
|
|
||||||
Log.d(TAG, "Waiting for the Godot main loop to start...")
|
Log.d(TAG, "Waiting for the Godot main loop to start...")
|
||||||
testPlugin.waitForGodotMainLoopStarted()
|
testPlugin.waitForGodotMainLoopStarted()
|
||||||
|
|
||||||
Log.d(TAG, "Running JavaClassWrapper tests...")
|
Log.d(TAG, "Running JavaClassWrapper tests...")
|
||||||
val result = testPlugin.runJavaClassWrapperTests()
|
val result = testPlugin.runJavaClassWrapperTests()
|
||||||
assertNotNull(result)
|
assertNotNull(result)
|
||||||
result.exceptionOrNull()?.let { throw it }
|
result.exceptionOrNull()?.let { throw it }
|
||||||
assertTrue(result.isSuccess)
|
assertTrue(result.isSuccess)
|
||||||
Log.d(TAG, "Passed ${result.getOrNull()} tests")
|
Log.d(TAG, "Passed ${result.getOrNull()} tests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test implicit launch of the Godot app, and validates this resolves to the `GodotAppLauncher` activity alias.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testImplicitGodotAppLauncherLaunch() {
|
||||||
|
val implicitLaunchIntent = Intent().apply {
|
||||||
|
setPackage(BuildConfig.APPLICATION_ID)
|
||||||
|
action = Intent.ACTION_MAIN
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotApp>(implicitLaunchIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNull(commandLineParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test explicit launch of the Godot app via its activity-alias launcher, and validates it resolves properly.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testExplicitGodotAppLauncherLaunch() {
|
||||||
|
val explicitIntent = Intent().apply {
|
||||||
|
component = ComponentName(BuildConfig.APPLICATION_ID, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotApp>(explicitIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, GODOT_APP_LAUNCHER_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNull(commandLineParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test explicit launch of the `GodotApp` activity.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testExplicitGodotAppLaunch() {
|
||||||
|
val explicitIntent = Intent().apply {
|
||||||
|
component = ComponentName(BuildConfig.APPLICATION_ID, GODOT_APP_CLASS_NAME)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotApp>(explicitIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, GODOT_APP_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNotNull(commandLineParams)
|
||||||
|
assertTrue(commandLineParams.contentEquals(TEST_COMMAND_LINE_PARAMS))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,23 +31,25 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotApp"
|
android:name=".GodotApp"
|
||||||
android:label="@string/godot_project_name_string"
|
|
||||||
android:theme="@style/GodotAppSplashTheme"
|
android:theme="@style/GodotAppSplashTheme"
|
||||||
android:launchMode="singleInstancePerTask"
|
android:launchMode="singleInstancePerTask"
|
||||||
android:excludeFromRecents="false"
|
android:excludeFromRecents="false"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||||
android:resizeableActivity="false"
|
android:resizeableActivity="false"
|
||||||
tools:ignore="UnusedAttribute" >
|
tools:ignore="UnusedAttribute" />
|
||||||
|
<activity-alias
|
||||||
|
android:name=".GodotAppLauncher"
|
||||||
|
android:targetActivity=".GodotApp"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity-alias>
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,17 @@ android {
|
|||||||
]
|
]
|
||||||
|
|
||||||
ndk { debugSymbolLevel 'NONE' }
|
ndk { debugSymbolLevel 'NONE' }
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
||||||
|
// The following argument makes the Android Test Orchestrator run its
|
||||||
|
// "pm clear" command after each test invocation. This command ensures
|
||||||
|
// that the app's state is completely cleared between tests.
|
||||||
|
testInstrumentationRunnerArguments clearPackageData: 'true'
|
||||||
|
}
|
||||||
|
|
||||||
|
testOptions {
|
||||||
|
execution 'ANDROIDX_TEST_ORCHESTRATOR'
|
||||||
}
|
}
|
||||||
|
|
||||||
base {
|
base {
|
||||||
@@ -196,4 +207,11 @@ dependencies {
|
|||||||
horizonosImplementation "org.godotengine:godot-openxr-vendors-meta:$versions.openxrVendorsVersion"
|
horizonosImplementation "org.godotengine:godot-openxr-vendors-meta:$versions.openxrVendorsVersion"
|
||||||
// Pico dependencies
|
// Pico dependencies
|
||||||
picoosImplementation "org.godotengine:godot-openxr-vendors-pico:$versions.openxrVendorsVersion"
|
picoosImplementation "org.godotengine:godot-openxr-vendors-pico:$versions.openxrVendorsVersion"
|
||||||
|
|
||||||
|
// Android instrumented test dependencies
|
||||||
|
androidTestImplementation "androidx.test.ext:junit:$versions.junitVersion"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCoreVersion"
|
||||||
|
androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$versions.kotlinTestVersion"
|
||||||
|
androidTestImplementation "androidx.test:runner:$versions.testRunnerVersion"
|
||||||
|
androidTestUtil "androidx.test:orchestrator:$versions.testOrchestratorVersion"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,117 @@
|
|||||||
|
/**************************************************************************/
|
||||||
|
/* GodotEditorTest.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 android.content.ComponentName
|
||||||
|
import android.content.Intent
|
||||||
|
import androidx.test.core.app.ActivityScenario
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import org.godotengine.godot.GodotActivity.Companion.EXTRA_COMMAND_LINE_PARAMS
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test for the Godot editor.
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class GodotEditorTest {
|
||||||
|
companion object {
|
||||||
|
private val TAG = GodotEditorTest::class.simpleName
|
||||||
|
|
||||||
|
private val TEST_COMMAND_LINE_PARAMS = arrayOf("This is a test")
|
||||||
|
private const val PROJECT_MANAGER_CLASS_NAME = "org.godotengine.editor.ProjectManager"
|
||||||
|
private const val GODOT_EDITOR_CLASS_NAME = "org.godotengine.editor.GodotEditor"
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implicitly launch the project manager.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testImplicitProjectManagerLaunch() {
|
||||||
|
val implicitLaunchIntent = Intent().apply {
|
||||||
|
setPackage(BuildConfig.APPLICATION_ID)
|
||||||
|
action = Intent.ACTION_MAIN
|
||||||
|
addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotEditor>(implicitLaunchIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, PROJECT_MANAGER_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNull(commandLineParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly launch the project manager.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testExplicitProjectManagerLaunch() {
|
||||||
|
val explicitProjectManagerIntent = Intent().apply {
|
||||||
|
component = ComponentName(BuildConfig.APPLICATION_ID, PROJECT_MANAGER_CLASS_NAME)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotEditor>(explicitProjectManagerIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, PROJECT_MANAGER_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNull(commandLineParams)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explicitly launch the `GodotEditor` activity.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun testExplicitGodotEditorLaunch() {
|
||||||
|
val godotEditorIntent = Intent().apply {
|
||||||
|
component = ComponentName(BuildConfig.APPLICATION_ID, GODOT_EDITOR_CLASS_NAME)
|
||||||
|
putExtra(EXTRA_COMMAND_LINE_PARAMS, TEST_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
ActivityScenario.launch<GodotEditor>(godotEditorIntent).use { scenario ->
|
||||||
|
scenario.onActivity { activity ->
|
||||||
|
assertEquals(activity.intent.component?.className, GODOT_EDITOR_CLASS_NAME)
|
||||||
|
|
||||||
|
val commandLineParams = activity.intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
assertNotNull(commandLineParams)
|
||||||
|
assertTrue(commandLineParams.contentEquals(TEST_COMMAND_LINE_PARAMS))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,20 +47,31 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotEditor"
|
android:name=".GodotEditor"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
tools:node="merge"
|
tools:node="merge"
|
||||||
tools:replace="android:screenOrientation">
|
tools:replace="android:screenOrientation">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
<category android:name="com.oculus.intent.category.2D" />
|
<category android:name="com.oculus.intent.category.2D" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|
||||||
<meta-data android:name="com.oculus.vrshell.free_resizing_lock_aspect_ratio" android:value="true"/>
|
<meta-data android:name="com.oculus.vrshell.free_resizing_lock_aspect_ratio" android:value="true"/>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity-alias
|
||||||
|
android:name=".ProjectManager"
|
||||||
|
android:exported="true"
|
||||||
|
tools:node="merge"
|
||||||
|
android:targetActivity=".GodotEditor">
|
||||||
|
<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>
|
||||||
|
</activity-alias>
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotXRGame"
|
android:name=".GodotXRGame"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name=".GodotEditor"
|
android:name=".GodotEditor"
|
||||||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:icon="@mipmap/themed_icon"
|
android:icon="@mipmap/themed_icon"
|
||||||
android:launchMode="singleTask"
|
android:launchMode="singleTask"
|
||||||
android:screenOrientation="userLandscape">
|
android:screenOrientation="userLandscape">
|
||||||
@@ -54,13 +54,6 @@
|
|||||||
android:defaultWidth="@dimen/editor_default_window_width"
|
android:defaultWidth="@dimen/editor_default_window_width"
|
||||||
android:defaultHeight="@dimen/editor_default_window_height" />
|
android:defaultHeight="@dimen/editor_default_window_height" />
|
||||||
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
|
|
||||||
<category android:name="android.intent.category.DEFAULT" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
|
|
||||||
<!-- Intent filter used to intercept hybrid PANEL launch for the current editor project, and route it
|
<!-- Intent filter used to intercept hybrid PANEL launch for the current editor project, and route it
|
||||||
properly through the editor 'run' logic (e.g: debugger setup) -->
|
properly through the editor 'run' logic (e.g: debugger setup) -->
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
@@ -77,6 +70,18 @@
|
|||||||
<category android:name="org.godotengine.xr.hybrid.IMMERSIVE" />
|
<category android:name="org.godotengine.xr.hybrid.IMMERSIVE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity-alias
|
||||||
|
android:name=".ProjectManager"
|
||||||
|
android:exported="true"
|
||||||
|
android:icon="@mipmap/themed_icon"
|
||||||
|
android:targetActivity=".GodotEditor">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity-alias>
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotGame"
|
android:name=".GodotGame"
|
||||||
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ import org.godotengine.editor.embed.GameMenuFragment
|
|||||||
import org.godotengine.editor.utils.signApk
|
import org.godotengine.editor.utils.signApk
|
||||||
import org.godotengine.editor.utils.verifyApk
|
import org.godotengine.editor.utils.verifyApk
|
||||||
import org.godotengine.godot.BuildConfig
|
import org.godotengine.godot.BuildConfig
|
||||||
|
import org.godotengine.godot.Godot
|
||||||
import org.godotengine.godot.GodotActivity
|
import org.godotengine.godot.GodotActivity
|
||||||
import org.godotengine.godot.GodotLib
|
import org.godotengine.godot.GodotLib
|
||||||
import org.godotengine.godot.editor.utils.EditorUtils
|
import org.godotengine.godot.editor.utils.EditorUtils
|
||||||
@@ -158,6 +159,20 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
internal const val SNACKBAR_SHOW_DURATION_MS = 5000L
|
internal const val SNACKBAR_SHOW_DURATION_MS = 5000L
|
||||||
|
|
||||||
private const val PREF_KEY_DONT_SHOW_GAME_RESUME_HINT = "pref_key_dont_show_game_resume_hint"
|
private const val PREF_KEY_DONT_SHOW_GAME_RESUME_HINT = "pref_key_dont_show_game_resume_hint"
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun isRunningInInstrumentation(): Boolean {
|
||||||
|
if (BuildConfig.BUILD_TYPE == "release") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return try {
|
||||||
|
Class.forName("org.godotengine.editor.GodotEditorTest")
|
||||||
|
true
|
||||||
|
} catch (_: ClassNotFoundException) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val editorMessageDispatcher = EditorMessageDispatcher(this)
|
internal val editorMessageDispatcher = EditorMessageDispatcher(this)
|
||||||
@@ -229,9 +244,15 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
}
|
}
|
||||||
|
|
||||||
// We exclude certain permissions from the set we request at startup, as they'll be
|
// Skip permissions request if running in a device farm (e.g. firebase test lab) or if requested via the launch
|
||||||
// requested on demand based on use cases.
|
// intent (e.g. instrumentation tests).
|
||||||
PermissionsUtil.requestManifestPermissions(this, getExcludedPermissions())
|
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.
|
||||||
|
PermissionsUtil.requestManifestPermissions(this, getExcludedPermissions())
|
||||||
|
}
|
||||||
|
|
||||||
editorMessageDispatcher.parseStartIntent(packageManager, intent)
|
editorMessageDispatcher.parseStartIntent(packageManager, intent)
|
||||||
|
|
||||||
@@ -247,7 +268,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
|
|
||||||
override fun onNewIntent(newIntent: Intent) {
|
override fun onNewIntent(newIntent: Intent) {
|
||||||
if (newIntent.hasCategory(HYBRID_APP_PANEL_CATEGORY) || newIntent.hasCategory(HYBRID_APP_IMMERSIVE_CATEGORY)) {
|
if (newIntent.hasCategory(HYBRID_APP_PANEL_CATEGORY) || newIntent.hasCategory(HYBRID_APP_IMMERSIVE_CATEGORY)) {
|
||||||
val params = newIntent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
val params = retrieveCommandLineParamsFromLaunchIntent(newIntent)
|
||||||
Log.d(TAG, "Received hybrid transition intent $newIntent with parameters ${params.contentToString()}")
|
Log.d(TAG, "Received hybrid transition intent $newIntent with parameters ${params.contentToString()}")
|
||||||
// Override EXTRA_NEW_LAUNCH so the editor is not restarted
|
// Override EXTRA_NEW_LAUNCH so the editor is not restarted
|
||||||
newIntent.putExtra(EXTRA_NEW_LAUNCH, false)
|
newIntent.putExtra(EXTRA_NEW_LAUNCH, false)
|
||||||
@@ -257,7 +278,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
var scene = ""
|
var scene = ""
|
||||||
var xrMode = XR_MODE_DEFAULT
|
var xrMode = XR_MODE_DEFAULT
|
||||||
var path = ""
|
var path = ""
|
||||||
if (params != null) {
|
if (params.isNotEmpty()) {
|
||||||
val sceneIndex = params.indexOf(SCENE_ARG)
|
val sceneIndex = params.indexOf(SCENE_ARG)
|
||||||
if (sceneIndex != -1 && sceneIndex + 1 < params.size) {
|
if (sceneIndex != -1 && sceneIndex + 1 < params.size) {
|
||||||
scene = params[sceneIndex +1]
|
scene = params[sceneIndex +1]
|
||||||
@@ -511,6 +532,14 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
|
|||||||
return editorWindowInfo.windowId
|
return editorWindowInfo.windowId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onGodotForceQuit(instance: Godot) {
|
||||||
|
if (!isRunningInInstrumentation()) {
|
||||||
|
// For instrumented tests, we disable force-quitting to allow the tests to complete successfully, otherwise
|
||||||
|
// they fail when the process crashes.
|
||||||
|
super.onGodotForceQuit(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final override fun onGodotForceQuit(godotInstanceId: Int): Boolean {
|
final override fun onGodotForceQuit(godotInstanceId: Int): Boolean {
|
||||||
val editorWindowInfo = getEditorWindowInfoForInstanceId(godotInstanceId) ?: return super.onGodotForceQuit(godotInstanceId)
|
val editorWindowInfo = getEditorWindowInfoForInstanceId(godotInstanceId) ?: return super.onGodotForceQuit(godotInstanceId)
|
||||||
|
|
||||||
|
|||||||
@@ -63,20 +63,18 @@ abstract class BaseGodotGame: GodotEditor() {
|
|||||||
|
|
||||||
// Check if we should be running in XR instead (if available) as it's possible we were
|
// 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.
|
// launched from the project manager which doesn't have that information.
|
||||||
val launchingArgs = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
val launchingArgs = retrieveCommandLineParamsFromLaunchIntent()
|
||||||
if (launchingArgs != null) {
|
val editorWindowInfo = retrieveEditorWindowInfo(launchingArgs, getEditorGameEmbedMode())
|
||||||
val editorWindowInfo = retrieveEditorWindowInfo(launchingArgs, getEditorGameEmbedMode())
|
if (editorWindowInfo != getEditorWindowInfo()) {
|
||||||
if (editorWindowInfo != getEditorWindowInfo()) {
|
val relaunchIntent = getNewGodotInstanceIntent(editorWindowInfo, launchingArgs)
|
||||||
val relaunchIntent = getNewGodotInstanceIntent(editorWindowInfo, launchingArgs)
|
relaunchIntent.putExtra(EXTRA_NEW_LAUNCH, true)
|
||||||
relaunchIntent.putExtra(EXTRA_NEW_LAUNCH, true)
|
.putExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD, intent.getBundleExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD))
|
||||||
.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()}")
|
Log.d(TAG, "Relaunching XR project using ${editorWindowInfo.windowClassName} with parameters ${launchingArgs.contentToString()}")
|
||||||
Godot.getInstance(applicationContext).destroyAndKillProcess {
|
Godot.getInstance(applicationContext).destroyAndKillProcess {
|
||||||
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
|
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request project runtime permissions if necessary.
|
// Request project runtime permissions if necessary.
|
||||||
|
|||||||
@@ -16,16 +16,10 @@
|
|||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotEditor"
|
android:name=".GodotEditor"
|
||||||
android:exported="true"
|
android:exported="false"
|
||||||
android:screenOrientation="landscape"
|
android:screenOrientation="landscape"
|
||||||
tools:node="merge"
|
tools:node="merge"
|
||||||
tools:replace="android:screenOrientation">
|
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" />
|
|
||||||
</intent-filter>
|
|
||||||
</activity>
|
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".GodotXRGame"
|
android:name=".GodotXRGame"
|
||||||
|
|||||||
@@ -72,18 +72,48 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
|
|||||||
protected var godotFragment: GodotFragment? = null
|
protected var godotFragment: GodotFragment? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Strip out the command line parameters from intent targeting exported activities.
|
||||||
|
*/
|
||||||
|
protected fun sanitizeLaunchIntent(launchIntent: Intent = intent): Intent {
|
||||||
|
val targetComponent = launchIntent.component ?: componentName
|
||||||
|
val activityInfo = packageManager.getActivityInfo(targetComponent, 0)
|
||||||
|
if (activityInfo.exported) {
|
||||||
|
launchIntent.removeExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
}
|
||||||
|
|
||||||
|
return launchIntent
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only retrieve the command line parameters from the intent from non-exported activities.
|
||||||
|
* This ensures only internal components can configure how the engine is run.
|
||||||
|
*/
|
||||||
|
protected fun retrieveCommandLineParamsFromLaunchIntent(launchIntent: Intent = intent): Array<String> {
|
||||||
|
val targetComponent = launchIntent.component ?: componentName
|
||||||
|
val activityInfo = packageManager.getActivityInfo(targetComponent, 0)
|
||||||
|
if (!activityInfo.exported) {
|
||||||
|
val params = launchIntent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
||||||
|
return params ?: emptyArray()
|
||||||
|
}
|
||||||
|
return emptyArray()
|
||||||
|
}
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
intent = sanitizeLaunchIntent(intent)
|
||||||
|
|
||||||
val assetsCommandLine = try {
|
val assetsCommandLine = try {
|
||||||
CommandLineFileParser.parseCommandLine(assets.open("_cl_"))
|
CommandLineFileParser.parseCommandLine(assets.open("_cl_"))
|
||||||
} catch (ignored: Exception) {
|
} catch (_: Exception) {
|
||||||
mutableListOf()
|
mutableListOf()
|
||||||
}
|
}
|
||||||
|
Log.d(TAG, "Project command line parameters: $assetsCommandLine")
|
||||||
commandLineParams.addAll(assetsCommandLine)
|
commandLineParams.addAll(assetsCommandLine)
|
||||||
|
|
||||||
val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
|
val intentCommandLine = retrieveCommandLineParamsFromLaunchIntent()
|
||||||
Log.d(TAG, "Starting intent $intent with parameters ${params.contentToString()}")
|
Log.d(TAG, "Launch intent $intent with parameters ${intentCommandLine.contentToString()}")
|
||||||
commandLineParams.addAll(params ?: emptyArray())
|
commandLineParams.addAll(intentCommandLine)
|
||||||
|
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
@@ -167,10 +197,9 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(newIntent: Intent) {
|
override fun onNewIntent(newIntent: Intent) {
|
||||||
super.onNewIntent(newIntent)
|
intent = sanitizeLaunchIntent(newIntent)
|
||||||
intent = newIntent
|
super.onNewIntent(intent)
|
||||||
|
handleStartIntent(intent, false)
|
||||||
handleStartIntent(newIntent, false)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
|
private fun handleStartIntent(intent: Intent, newLaunch: Boolean) {
|
||||||
|
|||||||
Reference in New Issue
Block a user