Skip to content

Commit 529a652

Browse files
authored
Merge pull request #119584 from m4gr3d/add_front_door_4_5
[4.5] [Android] Make use of activity-alias as the launcher mechanism for the Godot editor and the Godot app template
2 parents f085b04 + 2e9d1a6 commit 529a652

9 files changed

Lines changed: 120 additions & 57 deletions

File tree

platform/android/export/export_plugin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2497,7 +2497,7 @@ Error EditorExportPlatformAndroid::run(const Ref<EditorExportPreset> &p_preset,
24972497
print_verbose(output);
24982498
if (err || rv != 0 || output.contains("Error: Activity not started")) {
24992499
// The implicit launch failed, let's try an explicit launch by specifying the component name before giving up.
2500-
const String component_name = get_package_name(p_preset, package_name) + "/com.godot.game.GodotApp";
2500+
const String component_name = get_package_name(p_preset, package_name) + "/com.godot.game.GodotAppLauncher";
25012501
print_line("Implicit launch failed.. Trying explicit launch using", component_name);
25022502
args.erase(get_package_name(p_preset, package_name));
25032503
args.push_back("-n");

platform/android/export/gradle_export_util.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "gradle_export_util.h"
3232

3333
#include "core/config/project_settings.h"
34+
#include "modules/regex/regex.h"
3435

3536
int _get_android_orientation_value(DisplayServer::ScreenOrientation screen_orientation) {
3637
switch (screen_orientation) {
@@ -272,6 +273,19 @@ String _get_screen_sizes_tag(const Ref<EditorExportPreset> &p_preset) {
272273
}
273274

274275
String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, const Ref<EditorExportPreset> &p_preset, bool p_debug) {
276+
String export_plugins_activity_element_contents;
277+
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
278+
for (int i = 0; i < export_plugins.size(); i++) {
279+
if (export_plugins[i]->supports_platform(p_export_platform)) {
280+
const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
281+
if (!contents.is_empty()) {
282+
export_plugins_activity_element_contents += contents;
283+
export_plugins_activity_element_contents += "\n";
284+
}
285+
}
286+
}
287+
288+
// Update the GodotApp activity tag.
275289
String orientation = _get_android_orientation_label(DisplayServer::ScreenOrientation(int(p_export_platform->get_project_setting(p_preset, "display/window/handheld/orientation"))));
276290
String manifest_activity_text = vformat(
277291
" <activity android:name=\".GodotApp\" "
@@ -284,6 +298,21 @@ String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, con
284298
orientation,
285299
bool_to_string(bool(p_export_platform->get_project_setting(p_preset, "display/window/size/resizable"))));
286300

301+
// *LAUNCHER and *HOME categories should only go to the activity-alias.
302+
Ref<RegEx> activity_content_to_remove_regex = RegEx::create_from_string(R"delim(<category\s+android:name\s*=\s*"\S+(LAUNCHER|HOME)"\s*\/>)delim");
303+
String updated_export_plugins_activity_element_contents = activity_content_to_remove_regex->sub(export_plugins_activity_element_contents, "", true);
304+
305+
manifest_activity_text += updated_export_plugins_activity_element_contents;
306+
307+
manifest_activity_text += " </activity>\n";
308+
309+
// Update the GodotAppLauncher activity tag.
310+
manifest_activity_text += " <activity-alias\n"
311+
" tools:node=\"mergeOnlyAttributes\"\n"
312+
" android:name=\".GodotAppLauncher\"\n"
313+
" android:targetActivity=\".GodotApp\"\n"
314+
" android:exported=\"true\">\n";
315+
287316
manifest_activity_text += " <intent-filter>\n"
288317
" <action android:name=\"android.intent.action.MAIN\" />\n"
289318
" <category android:name=\"android.intent.category.DEFAULT\" />\n";
@@ -305,18 +334,12 @@ String _get_activity_tag(const Ref<EditorExportPlatform> &p_export_platform, con
305334

306335
manifest_activity_text += " </intent-filter>\n";
307336

308-
Vector<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
309-
for (int i = 0; i < export_plugins.size(); i++) {
310-
if (export_plugins[i]->supports_platform(p_export_platform)) {
311-
const String contents = export_plugins[i]->get_android_manifest_activity_element_contents(p_export_platform, p_debug);
312-
if (!contents.is_empty()) {
313-
manifest_activity_text += contents;
314-
manifest_activity_text += "\n";
315-
}
316-
}
317-
}
337+
// Hybrid categories should only go to the actual 'GodotApp' activity.
338+
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");
339+
String updated_export_plugins_activity_alias_element_contents = activity_alias_content_to_remove_regex->sub(export_plugins_activity_element_contents, "", true);
340+
manifest_activity_text += updated_export_plugins_activity_alias_element_contents;
318341

319-
manifest_activity_text += " </activity>\n";
342+
manifest_activity_text += " </activity-alias>\n";
320343
return manifest_activity_text;
321344
}
322345

platform/android/java/app/AndroidManifest.xml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,26 @@
3131

3232
<activity
3333
android:name=".GodotApp"
34-
android:label="@string/godot_project_name_string"
3534
android:theme="@style/GodotAppSplashTheme"
3635
android:launchMode="singleInstancePerTask"
3736
android:excludeFromRecents="false"
38-
android:exported="true"
37+
android:exported="false"
3938
android:screenOrientation="landscape"
4039
android:windowSoftInputMode="adjustResize"
4140
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
4241
android:resizeableActivity="false"
43-
tools:ignore="UnusedAttribute" >
42+
tools:ignore="UnusedAttribute" />
43+
<activity-alias
44+
android:name=".GodotAppLauncher"
45+
android:targetActivity=".GodotApp"
46+
android:exported="true">
4447

4548
<intent-filter>
4649
<action android:name="android.intent.action.MAIN" />
4750
<category android:name="android.intent.category.DEFAULT" />
4851
<category android:name="android.intent.category.LAUNCHER" />
4952
</intent-filter>
50-
</activity>
53+
</activity-alias>
5154

5255
</application>
5356

platform/android/java/editor/src/horizonos/AndroidManifest.xml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,31 @@
4747

4848
<activity
4949
android:name=".GodotEditor"
50-
android:exported="true"
50+
android:exported="false"
5151
android:screenOrientation="landscape"
5252
tools:node="merge"
5353
tools:replace="android:screenOrientation">
5454
<intent-filter>
5555
<action android:name="android.intent.action.MAIN" />
5656
<category android:name="android.intent.category.DEFAULT" />
57-
<category android:name="android.intent.category.LAUNCHER" />
5857
<category android:name="com.oculus.intent.category.2D" />
5958
</intent-filter>
6059

6160
<meta-data android:name="com.oculus.vrshell.free_resizing_lock_aspect_ratio" android:value="true"/>
6261
</activity>
62+
<activity-alias
63+
android:name=".ProjectManager"
64+
android:exported="true"
65+
tools:node="merge"
66+
android:targetActivity=".GodotEditor">
67+
<intent-filter>
68+
<action android:name="android.intent.action.MAIN" />
6369

70+
<category android:name="android.intent.category.DEFAULT" />
71+
<category android:name="android.intent.category.LAUNCHER" />
72+
<category android:name="com.oculus.intent.category.2D" />
73+
</intent-filter>
74+
</activity-alias>
6475
<activity
6576
android:name=".GodotXRGame"
6677
android:exported="false"

platform/android/java/editor/src/main/AndroidManifest.xml

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,14 @@
4646
<activity
4747
android:name=".GodotEditor"
4848
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"
49-
android:exported="true"
49+
android:exported="false"
5050
android:icon="@mipmap/themed_icon"
5151
android:launchMode="singleTask"
5252
android:screenOrientation="userLandscape">
5353
<layout
5454
android:defaultWidth="@dimen/editor_default_window_width"
5555
android:defaultHeight="@dimen/editor_default_window_height" />
5656

57-
<intent-filter>
58-
<action android:name="android.intent.action.MAIN" />
59-
60-
<category android:name="android.intent.category.DEFAULT" />
61-
<category android:name="android.intent.category.LAUNCHER" />
62-
</intent-filter>
63-
6457
<!-- Intent filter used to intercept hybrid PANEL launch for the current editor project, and route it
6558
properly through the editor 'run' logic (e.g: debugger setup) -->
6659
<intent-filter>
@@ -77,6 +70,18 @@
7770
<category android:name="org.godotengine.xr.hybrid.IMMERSIVE" />
7871
</intent-filter>
7972
</activity>
73+
<activity-alias
74+
android:name=".ProjectManager"
75+
android:exported="true"
76+
android:icon="@mipmap/themed_icon"
77+
android:targetActivity=".GodotEditor">
78+
<intent-filter>
79+
<action android:name="android.intent.action.MAIN" />
80+
81+
<category android:name="android.intent.category.DEFAULT" />
82+
<category android:name="android.intent.category.LAUNCHER" />
83+
</intent-filter>
84+
</activity-alias>
8085
<activity
8186
android:name=".GodotGame"
8287
android:configChanges="layoutDirection|locale|orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode"

platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotEditor.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
241241

242242
override fun onNewIntent(newIntent: Intent) {
243243
if (newIntent.hasCategory(HYBRID_APP_PANEL_CATEGORY) || newIntent.hasCategory(HYBRID_APP_IMMERSIVE_CATEGORY)) {
244-
val params = newIntent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
244+
val params = retrieveCommandLineParamsFromLaunchIntent(newIntent)
245245
Log.d(TAG, "Received hybrid transition intent $newIntent with parameters ${params.contentToString()}")
246246
// Override EXTRA_NEW_LAUNCH so the editor is not restarted
247247
newIntent.putExtra(EXTRA_NEW_LAUNCH, false)
@@ -251,7 +251,7 @@ abstract class BaseGodotEditor : GodotActivity(), GameMenuFragment.GameMenuListe
251251
var scene = ""
252252
var xrMode = XR_MODE_DEFAULT
253253
var path = ""
254-
if (params != null) {
254+
if (params.isNotEmpty()) {
255255
val sceneIndex = params.indexOf(SCENE_ARG)
256256
if (sceneIndex != -1 && sceneIndex + 1 < params.size) {
257257
scene = params[sceneIndex +1]

platform/android/java/editor/src/main/java/org/godotengine/editor/BaseGodotGame.kt

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -62,20 +62,18 @@ abstract class BaseGodotGame: GodotEditor() {
6262

6363
// Check if we should be running in XR instead (if available) as it's possible we were
6464
// launched from the project manager which doesn't have that information.
65-
val launchingArgs = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
66-
if (launchingArgs != null) {
67-
val editorWindowInfo = retrieveEditorWindowInfo(launchingArgs, getEditorGameEmbedMode())
68-
if (editorWindowInfo != getEditorWindowInfo()) {
69-
val relaunchIntent = getNewGodotInstanceIntent(editorWindowInfo, launchingArgs)
70-
relaunchIntent.putExtra(EXTRA_NEW_LAUNCH, true)
71-
.putExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD, intent.getBundleExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD))
72-
73-
Log.d(TAG, "Relaunching XR project using ${editorWindowInfo.windowClassName} with parameters ${launchingArgs.contentToString()}")
74-
Godot.getInstance(applicationContext).destroyAndKillProcess {
75-
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
76-
}
77-
return
65+
val launchingArgs = retrieveCommandLineParamsFromLaunchIntent()
66+
val editorWindowInfo = retrieveEditorWindowInfo(launchingArgs, getEditorGameEmbedMode())
67+
if (editorWindowInfo != getEditorWindowInfo()) {
68+
val relaunchIntent = getNewGodotInstanceIntent(editorWindowInfo, launchingArgs)
69+
relaunchIntent.putExtra(EXTRA_NEW_LAUNCH, true)
70+
.putExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD, intent.getBundleExtra(EditorMessageDispatcher.EXTRA_MSG_DISPATCHER_PAYLOAD))
71+
72+
Log.d(TAG, "Relaunching XR project using ${editorWindowInfo.windowClassName} with parameters ${launchingArgs.contentToString()}")
73+
Godot.getInstance(applicationContext).destroyAndKillProcess {
74+
ProcessPhoenix.triggerRebirth(this, relaunchIntent)
7875
}
76+
return
7977
}
8078

8179
// Request project runtime permissions if necessary.

platform/android/java/editor/src/picoos/AndroidManifest.xml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,10 @@
1616

1717
<activity
1818
android:name=".GodotEditor"
19-
android:exported="true"
19+
android:exported="false"
2020
android:screenOrientation="landscape"
2121
tools:node="merge"
22-
tools:replace="android:screenOrientation">
23-
<intent-filter>
24-
<action android:name="android.intent.action.MAIN" />
25-
<category android:name="android.intent.category.DEFAULT" />
26-
<category android:name="android.intent.category.LAUNCHER" />
27-
</intent-filter>
28-
</activity>
22+
tools:replace="android:screenOrientation"/>
2923

3024
<activity
3125
android:name=".GodotXRGame"

platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,18 +72,48 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
7272
protected var godotFragment: GodotFragment? = null
7373
private set
7474

75+
/**
76+
* Strip out the command line parameters from intent targeting exported activities.
77+
*/
78+
protected fun sanitizeLaunchIntent(launchIntent: Intent = intent): Intent {
79+
val targetComponent = launchIntent.component ?: componentName
80+
val activityInfo = packageManager.getActivityInfo(targetComponent, 0)
81+
if (activityInfo.exported) {
82+
launchIntent.removeExtra(EXTRA_COMMAND_LINE_PARAMS)
83+
}
84+
85+
return launchIntent
86+
}
87+
88+
/**
89+
* Only retrieve the command line parameters from the intent from non-exported activities.
90+
* This ensures only internal components can configure how the engine is run.
91+
*/
92+
protected fun retrieveCommandLineParamsFromLaunchIntent(launchIntent: Intent = intent): Array<String> {
93+
val targetComponent = launchIntent.component ?: componentName
94+
val activityInfo = packageManager.getActivityInfo(targetComponent, 0)
95+
if (!activityInfo.exported) {
96+
val params = launchIntent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
97+
return params ?: emptyArray()
98+
}
99+
return emptyArray()
100+
}
101+
75102
@CallSuper
76103
override fun onCreate(savedInstanceState: Bundle?) {
104+
intent = sanitizeLaunchIntent(intent)
105+
77106
val assetsCommandLine = try {
78107
CommandLineFileParser.parseCommandLine(assets.open("_cl_"))
79-
} catch (ignored: Exception) {
108+
} catch (_: Exception) {
80109
mutableListOf()
81110
}
111+
Log.d(TAG, "Project command line parameters: $assetsCommandLine")
82112
commandLineParams.addAll(assetsCommandLine)
83113

84-
val params = intent.getStringArrayExtra(EXTRA_COMMAND_LINE_PARAMS)
85-
Log.d(TAG, "Starting intent $intent with parameters ${params.contentToString()}")
86-
commandLineParams.addAll(params ?: emptyArray())
114+
val intentCommandLine = retrieveCommandLineParamsFromLaunchIntent()
115+
Log.d(TAG, "Launch intent $intent with parameters ${intentCommandLine.contentToString()}")
116+
commandLineParams.addAll(intentCommandLine)
87117

88118
super.onCreate(savedInstanceState)
89119

@@ -167,10 +197,9 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
167197
}
168198

169199
override fun onNewIntent(newIntent: Intent) {
170-
super.onNewIntent(newIntent)
171-
intent = newIntent
172-
173-
handleStartIntent(newIntent, false)
200+
intent = sanitizeLaunchIntent(newIntent)
201+
super.onNewIntent(intent)
202+
handleStartIntent(intent, false)
174203
}
175204

176205
private fun handleStartIntent(intent: Intent, newLaunch: Boolean) {

0 commit comments

Comments
 (0)