Skip to content

Commit

Permalink
Update the configuration and launch mechanism for the hybrid app feature
Browse files Browse the repository at this point in the history
  • Loading branch information
m4gr3d committed Mar 9, 2025
1 parent 1f4d075 commit ed88604
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 53 deletions.
23 changes: 18 additions & 5 deletions plugin/src/main/cpp/export/export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,15 @@ Dictionary OpenXREditorExportPlugin::_get_vendor_toggle_option(const String &ven
true);
}

OpenXREditorExportPlugin::HybridType OpenXREditorExportPlugin::_get_hybrid_app_setting_value() const {
return (HybridType)(int)ProjectSettings::get_singleton()->get_setting_with_override("xr/openxr/hybrid_app");
bool OpenXREditorExportPlugin::_is_hybrid_app_enabled() const {
return ProjectSettings::get_singleton()-> get_setting_with_override("xr/hybrid_app/enabled");
}

OpenXRHybridApp::HybridMode OpenXREditorExportPlugin::_get_hybrid_app_launch_mode() const {
if (!_is_hybrid_app_enabled()) {
return OpenXRHybridApp::HYBRID_MODE_NONE;
}
return (OpenXRHybridApp::HybridMode)(int) ProjectSettings::get_singleton()->get_setting_with_override("xr/hybrid_app/launch_mode");
}

String OpenXREditorExportPlugin::_get_opening_activity_tag_for_panel_app() const {
Expand Down Expand Up @@ -127,6 +134,12 @@ String OpenXREditorExportPlugin::_get_common_activity_intent_filter_contents() c
<category android:name="android.intent.category.HOME" />
)";
}

if (_is_hybrid_app_enabled()) {
contents += R"(
<category android:name="org.godotengine.xr.hybrid.IMMERSIVE" />
)";
}
return contents;
}

Expand Down Expand Up @@ -198,11 +211,11 @@ Dictionary OpenXREditorExportPlugin::_get_export_options_overrides(const Ref<Edi
return overrides;
}

HybridType hybrid_type = _get_hybrid_app_setting_value();
if (hybrid_type != HYBRID_TYPE_DISABLED) {
OpenXRHybridApp::HybridMode hybrid_launch_mode = _get_hybrid_app_launch_mode();
if (hybrid_launch_mode != OpenXRHybridApp::HYBRID_MODE_NONE) {
// Unless this is a hybrid app that launches as a panel, then we want to force this option on.
// Otherwise, it needs to be off, so that the panel activity can be the one that's launched by default.
overrides["package/show_in_app_library"] = (hybrid_type != HYBRID_TYPE_START_AS_PANEL);
overrides["package/show_in_app_library"] = (hybrid_launch_mode != OpenXRHybridApp::HYBRID_MODE_PANEL);
}

return overrides;
Expand Down
11 changes: 7 additions & 4 deletions plugin/src/main/cpp/export/meta_export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ PackedStringArray MetaEditorExportPlugin::_get_export_features(const Ref<EditorE
}

// Add a feature to indicate that this is a hybrid app.
if (_is_openxr_enabled() && _get_hybrid_app_setting_value() != HYBRID_TYPE_DISABLED) {
if (_is_openxr_enabled() && _is_hybrid_app_enabled()) {
features.append(HYBRID_APP_FEATURE);
}

Expand Down Expand Up @@ -514,17 +514,18 @@ String MetaEditorExportPlugin::_get_android_manifest_application_element_content
contents += " <meta-data android:name=\"com.oculus.ossplash.background\" android:value=\"passthrough-contextual\" />\n";
}

HybridType hybrid_type = _get_hybrid_app_setting_value();
if (hybrid_type != HYBRID_TYPE_DISABLED) {
OpenXRHybridApp::HybridMode hybrid_launch_mode = _get_hybrid_app_launch_mode();
if (hybrid_launch_mode != OpenXRHybridApp::HYBRID_MODE_NONE) {
contents += _get_opening_activity_tag_for_panel_app();

contents +=
" <intent-filter>\n"
" <action android:name=\"android.intent.action.MAIN\" />\n"
" <category android:name=\"android.intent.category.DEFAULT\" />\n"
" <category android:name=\"org.godotengine.xr.hybrid.PANEL\" />\n"
" <category android:name=\"com.oculus.intent.category.2D\" />\n";

if (hybrid_type == HYBRID_TYPE_START_AS_PANEL) {
if (hybrid_launch_mode == OpenXRHybridApp::HYBRID_MODE_PANEL) {
contents += " <category android:name=\"android.intent.category.LAUNCHER\" />\n";
}

Expand All @@ -545,6 +546,8 @@ String MetaEditorExportPlugin::_get_android_manifest_activity_element_contents(c
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
<!-- Enable access to OpenXR on Oculus mobile devices, no-op on other Android
platforms. -->
<category android:name="com.oculus.intent.category.VR" />
Expand Down
11 changes: 4 additions & 7 deletions plugin/src/main/cpp/include/export/export_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

#pragma once

#include "classes/openxr_hybrid_app.h"

#include <godot_cpp/classes/display_server.hpp>
#include <godot_cpp/classes/editor_export_platform.hpp>
#include <godot_cpp/classes/editor_export_plugin.hpp>
Expand Down Expand Up @@ -70,12 +72,6 @@ class OpenXREditorExportPlugin : public EditorExportPlugin {
GDCLASS(OpenXREditorExportPlugin, EditorExportPlugin)

public:
enum HybridType {
HYBRID_TYPE_DISABLED,
HYBRID_TYPE_START_AS_IMMERSIVE,
HYBRID_TYPE_START_AS_PANEL,
};

OpenXREditorExportPlugin();

String _get_name() const override;
Expand Down Expand Up @@ -114,7 +110,8 @@ class OpenXREditorExportPlugin : public EditorExportPlugin {

Dictionary _get_vendor_toggle_option(const String &vendor_name) const;

HybridType _get_hybrid_app_setting_value() const;
bool _is_hybrid_app_enabled() const;
OpenXRHybridApp::HybridMode _get_hybrid_app_launch_mode() const;

String _get_opening_activity_tag_for_panel_app() const;

Expand Down
35 changes: 24 additions & 11 deletions plugin/src/main/cpp/register_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -291,19 +291,32 @@ void add_plugin_project_settings() {
}

{
String hybrid_app_setting = "xr/openxr/hybrid_app";
if (!project_settings->has_setting(hybrid_app_setting)) {
project_settings->set_setting(hybrid_app_setting, OpenXRHybridApp::HYBRID_MODE_NONE);
String hybrid_app_enabled_setting = "xr/hybrid_app/enabled";
if (!project_settings->has_setting(hybrid_app_enabled_setting)) {
project_settings->set_setting(hybrid_app_enabled_setting, false);
}

project_settings->set_initial_value(hybrid_app_setting, OpenXRHybridApp::HYBRID_MODE_NONE);
project_settings->set_as_basic(hybrid_app_setting, false);
Dictionary property_info;
property_info["name"] = hybrid_app_setting;
property_info["type"] = Variant::Type::INT;
property_info["hint"] = PROPERTY_HINT_ENUM;
property_info["hint_string"] = "Disabled:-1,Start As Immersive:0,Start As Panel:1";
project_settings->add_property_info(property_info);
project_settings->set_initial_value(hybrid_app_enabled_setting, false);
project_settings->set_as_basic(hybrid_app_enabled_setting, true);
Dictionary hybrid_app_enabled_property_info;
hybrid_app_enabled_property_info["name"] = hybrid_app_enabled_setting;
hybrid_app_enabled_property_info["type"] = Variant::Type::BOOL;
hybrid_app_enabled_property_info["hint"] = PROPERTY_HINT_NONE;
project_settings->add_property_info(hybrid_app_enabled_property_info);

String hybrid_app_launch_mode_setting = "xr/hybrid_app/launch_mode";
if (!project_settings->has_setting(hybrid_app_launch_mode_setting)) {
project_settings->set_setting(hybrid_app_launch_mode_setting, OpenXRHybridApp::HYBRID_MODE_IMMERSIVE);
}

project_settings->set_initial_value(hybrid_app_launch_mode_setting, OpenXRHybridApp::HYBRID_MODE_IMMERSIVE);
project_settings->set_as_basic(hybrid_app_launch_mode_setting, true);
Dictionary hybrid_app_launch_mode_property_info;
hybrid_app_launch_mode_property_info["name"] = hybrid_app_launch_mode_setting;
hybrid_app_launch_mode_property_info["type"] = Variant::Type::INT;
hybrid_app_launch_mode_property_info["hint"] = PROPERTY_HINT_ENUM;
hybrid_app_launch_mode_property_info["hint_string"] = "Start As Immersive:0,Start As Panel:1";
project_settings->add_property_info(hybrid_app_launch_mode_property_info);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@
package org.godotengine.openxr.vendors

import android.app.Activity
import android.content.ComponentName
import android.content.Intent
import android.util.Log
import android.view.View;
import android.view.View
import org.godotengine.godot.Godot
import org.godotengine.godot.GodotHost
import org.godotengine.godot.GodotLib
import org.godotengine.godot.plugin.GodotPlugin
import org.godotengine.godot.plugin.UsedByGodot
import org.godotengine.godot.utils.isNativeXRDevice
Expand All @@ -44,47 +44,85 @@ import org.godotengine.godot.utils.isNativeXRDevice
*/
class GodotOpenXRHybridAppInternal(godot: Godot?) : GodotPlugin(godot) {
companion object {
protected val TAG = GodotOpenXRHybridAppInternal::class.java.simpleName
private val TAG = GodotOpenXRHybridAppInternal::class.java.simpleName

private const val IMMERSIVE_ACTIVITY = "com.godot.game.GodotApp"
private const val PANEL_ACTIVITY = "org.godotengine.openxr.vendors.GodotPanelApp"
private const val EXTRA_HYBRID_LAUNCH_DATA = "godot_openxr_vendors_hybrid_launch_data"

private const val IMMERSIVE_MODE = 0
private const val PANEL_MODE = 1
// TODO: Duplicate from the Godot Android library; should remove once the lib dependency
// is updated
const val HYBRID_APP_PANEL_FEATURE = "godot_openxr_panel_app"
const val HYBRID_APP_PANEL_CATEGORY = "org.godotengine.xr.hybrid.PANEL"
const val HYBRID_APP_IMMERSIVE_CATEGORY = "org.godotengine.xr.hybrid.IMMERSIVE"

private const val INTENT_EXTRA_DATA = "godot_openxr_vendors_data"
private fun getHybridMode(activity: Activity?): HybridMode {
if (activity !is GodotHost) {
return HybridMode.NONE
}

// Check if hybrid is enabled
val hybridEnabled = GodotLib.getGlobal("xr/hybrid_app/enabled").toBoolean()
if (!hybridEnabled) {
return HybridMode.NONE
}

if (activity.supportsFeature(HYBRID_APP_PANEL_FEATURE)) {
return HybridMode.PANEL
}

return HybridMode.IMMERSIVE
}
}

private var hybridMode: Int = IMMERSIVE_MODE
/**
* Should match OpenXRHybridApp#HybridMode.
*/
private enum class HybridMode(private val nativeValue: Int) {
NONE( -1),
IMMERSIVE(0),
PANEL(1);

companion object {
fun fromNative(nativeValue: Int): HybridMode {
for (mode in HybridMode.entries) {
if (mode.nativeValue == nativeValue) {
return mode
}
}
return NONE
}
}
}

private var hybridMode = HybridMode.IMMERSIVE
private var hybridLaunchData: String = ""

override fun getPluginName() = "GodotOpenXRHybridAppInternal"

override fun onMainCreate(activity: Activity): View? {
if (activity::class.qualifiedName == PANEL_ACTIVITY) {
hybridMode = PANEL_MODE
} else {
hybridMode = IMMERSIVE_MODE
}

hybridLaunchData = activity.intent.getStringExtra(INTENT_EXTRA_DATA) ?: ""

hybridLaunchData = activity.intent.getStringExtra(EXTRA_HYBRID_LAUNCH_DATA) ?: ""
return null
}

override fun onGodotSetupCompleted() {
super.onGodotSetupCompleted()
hybridMode = getHybridMode(activity)
}

@UsedByGodot
fun hybridAppSwitchTo(mode: Int, data: String = ""): Boolean {
fun hybridAppSwitchTo(modeValue: Int, data: String = ""): Boolean {
val mode = HybridMode.fromNative(modeValue)
if (hybridMode == mode) return false

val context = getActivity() ?: return false
val context = activity ?: return false

if (!isNativeXRDevice(context)) return false

val activityName = if (mode == IMMERSIVE_MODE) IMMERSIVE_ACTIVITY else PANEL_ACTIVITY
val newInstance = Intent()
.setComponent(ComponentName(context, activityName))
val hybridCategory = if (mode == HybridMode.IMMERSIVE) HYBRID_APP_IMMERSIVE_CATEGORY else HYBRID_APP_PANEL_CATEGORY
val newInstance = Intent(Intent.ACTION_MAIN)
.addCategory(hybridCategory)
.setPackage(context.packageName)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(INTENT_EXTRA_DATA, data)
.putExtra(EXTRA_HYBRID_LAUNCH_DATA, data)

val godot = godot
if (godot != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ class GodotPanelApp : GodotActivity() {
}

override fun supportsFeature(featureTag: String): Boolean {
if ("godot_openxr_panel_app" == featureTag) {
if (GodotOpenXRHybridAppInternal.HYBRID_APP_PANEL_FEATURE == featureTag) {
return true
}

Expand Down
1 change: 1 addition & 0 deletions samples/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
*/.godot/
*/addons/godotopenxrvendors
*/android/
builds/
3 changes: 2 additions & 1 deletion samples/hybrid-app-sample/project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,5 @@ openxr/foveation_level=3
openxr/foveation_dynamic=true
openxr/startup_alert=false
shaders/enabled=true
openxr/hybrid_app=1
hybrid_app/enabled=true
hybrid_app/launch_mode=1

0 comments on commit ed88604

Please sign in to comment.