Skip to content

Commit

Permalink
Support making hybrid apps for Pico headsets
Browse files Browse the repository at this point in the history
  • Loading branch information
dsnopek committed Jan 15, 2025
1 parent 41ecb73 commit f09e254
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 3 deletions.
51 changes: 51 additions & 0 deletions plugin/src/main/cpp/export/pico_export_plugin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,27 @@ TypedArray<Dictionary> PicoEditorExportPlugin::_get_export_options(const Ref<Edi
export_options.append(_eye_tracking_option);
export_options.append(_face_tracking_option);
export_options.append(_hand_tracking_option);
export_options.append(_get_hybrid_app_option("pico_xr_features"));

return export_options;
}

Dictionary PicoEditorExportPlugin::_get_export_options_overrides(const Ref<EditorExportPlatform> &platform) const {
Dictionary overrides;
if (!_supports_platform(platform) || !_is_vendor_plugin_enabled()) {
return overrides;
}

HybridType hybrid_type = _get_hybrid_app_option_value();
if (hybrid_type != HYBRID_TYPE_DISABLED) {
// 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);
}

return overrides;
}

bool PicoEditorExportPlugin::_is_eye_tracking_enabled() const {
bool eye_tracking_project_setting_enabled = ProjectSettings::get_singleton()->get_setting_with_override("xr/openxr/extensions/eye_gaze_interaction");
if (!eye_tracking_project_setting_enabled) {
Expand All @@ -119,6 +136,11 @@ PackedStringArray PicoEditorExportPlugin::_get_export_features(const Ref<EditorE
features.append(EYE_GAZE_INTERACTION_FEATURE);
}

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

return features;
}

Expand Down Expand Up @@ -200,5 +222,34 @@ String PicoEditorExportPlugin::_get_android_manifest_application_element_content
contents += " <meta-data tools:node=\"replace\" android:name=\"Hand_Tracking_HighFrequency\" android:value=\"1\" />\n";
}

HybridType hybrid_type = _get_hybrid_app_option_value();
if (hybrid_type != HYBRID_TYPE_DISABLED) {
contents += " <meta-data tools:node=\"replace\" android:name=\"pvr.app.type\" android:value=\"2d\" />\n";

contents +=
" <activity android:name=\"org.godotengine.openxr.vendors.GodotPanelApp\" "
"android:process=\":GodotPanelApp\" "
"android:label=\"@string/godot_project_name_string\" "
"android:theme=\"@style/GodotAppSplashTheme\" "
"android:launchMode=\"singleInstancePerTask\" "
"android:excludeFromRecents=\"false\" "
"android:exported=\"true\" "
"android:screenOrientation=\"landscape\" "
"android:configChanges=\"orientation|keyboardHidden|screenSize|smallestScreenSize|density|keyboard|navigation|screenLayout|uiMode\" "
"android:resizeableActivity=\"true\" "
"tools:ignore=\"UnusedAttribute\" >\n"
" <intent-filter>\n"
" <action android:name=\"android.intent.action.MAIN\" />\n"
" <category android:name=\"android.intent.category.DEFAULT\" />\n";

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

contents +=
" </intent-filter>\n"
" </activity>\n";
}

return contents;
}
5 changes: 5 additions & 0 deletions plugin/src/main/cpp/include/export/pico_export_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class PicoEditorExportPlugin : public OpenXREditorExportPlugin {
PicoEditorExportPlugin();

TypedArray<Dictionary> _get_export_options(const Ref<EditorExportPlatform> &platform) const override;
Dictionary _get_export_options_overrides(const Ref<EditorExportPlatform> &p_platform) const override;

PackedStringArray _get_export_features(const Ref<EditorExportPlatform> &platform, bool debug) const override;

Expand All @@ -67,6 +68,10 @@ class PicoEditorExportPlugin : public OpenXREditorExportPlugin {
protected:
static void _bind_methods();

virtual HybridType _get_hybrid_app_option_value() const override {
return (HybridType)_get_int_option(_get_hybrid_app_option_name("pico_xr_features"), HYBRID_TYPE_DISABLED);
}

Dictionary _eye_tracking_option;
Dictionary _face_tracking_option;
Dictionary _hand_tracking_option;
Expand Down
3 changes: 3 additions & 0 deletions plugin/src/pico/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
<meta-data android:name="org.godotengine.plugin.v2.GodotOpenXRPico"
android:value="org.godotengine.openxr.vendors.pico.GodotOpenXRPico" />

<meta-data android:name="org.godotengine.plugin.v2.GodotOpenXRHybridAppInternal"
android:value="org.godotengine.openxr.vendors.GodotOpenXRHybridAppInternal" />

<!-- Enable VR mode on Pico headsets -->
<meta-data android:name="pvr.app.type" android:value="vr" />
<meta-data android:name="pvr.sdk.version" android:value="OpenXR" />";
Expand Down
253 changes: 252 additions & 1 deletion samples/hybrid-app-sample/export_presets.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

name="Quest"
platform="Android"
runnable=true
runnable=false
advanced_options=true
dedicated_server=false
custom_features=""
Expand Down Expand Up @@ -246,3 +246,254 @@ pico_xr_features/face_tracking=0
pico_xr_features/hand_tracking=0
xr_features/enable_magicleap_plugin=false
magicleap_xr_features/hand_tracking=0
pico_xr_features/hybrid_app=0

[preset.1]

name="Pico"
platform="Android"
runnable=true
advanced_options=false
dedicated_server=false
custom_features=""
export_filter="all_resources"
include_filter=""
exclude_filter=""
export_path=""
patches=PackedStringArray()
encryption_include_filters=""
encryption_exclude_filters=""
seed=0
encrypt_pck=false
encrypt_directory=false
script_export_mode=2

[preset.1.options]

custom_template/debug=""
custom_template/release=""
gradle_build/use_gradle_build=true
gradle_build/gradle_build_directory=""
gradle_build/android_source_template=""
gradle_build/compress_native_libraries=false
gradle_build/export_format=0
gradle_build/min_sdk=""
gradle_build/target_sdk=""
architectures/armeabi-v7a=false
architectures/arm64-v8a=true
architectures/x86=false
architectures/x86_64=false
version/code=1
version/name=""
package/unique_name="com.godotopenxrvendors.picohybridappsample"
package/name=""
package/signed=true
package/app_category=2
package/retain_data_on_uninstall=false
package/exclude_from_recents=false
package/show_in_android_tv=false
package/show_in_app_library=true
package/show_as_launcher_app=false
launcher_icons/main_192x192=""
launcher_icons/adaptive_foreground_432x432=""
launcher_icons/adaptive_background_432x432=""
launcher_icons/adaptive_monochrome_432x432=""
graphics/opengl_debug=false
xr_features/xr_mode=1
wear_os/swipe_to_dismiss=true
screen/immersive_mode=true
screen/support_small=true
screen/support_normal=true
screen/support_large=true
screen/support_xlarge=true
user_data_backup/allow=false
command_line/extra_args=""
apk_expansion/enable=false
apk_expansion/SALT=""
apk_expansion/public_key=""
permissions/custom_permissions=PackedStringArray()
permissions/access_checkin_properties=false
permissions/access_coarse_location=false
permissions/access_fine_location=false
permissions/access_location_extra_commands=false
permissions/access_media_location=false
permissions/access_mock_location=false
permissions/access_network_state=false
permissions/access_surface_flinger=false
permissions/access_wifi_state=false
permissions/account_manager=false
permissions/add_voicemail=false
permissions/authenticate_accounts=false
permissions/battery_stats=false
permissions/bind_accessibility_service=false
permissions/bind_appwidget=false
permissions/bind_device_admin=false
permissions/bind_input_method=false
permissions/bind_nfc_service=false
permissions/bind_notification_listener_service=false
permissions/bind_print_service=false
permissions/bind_remoteviews=false
permissions/bind_text_service=false
permissions/bind_vpn_service=false
permissions/bind_wallpaper=false
permissions/bluetooth=false
permissions/bluetooth_admin=false
permissions/bluetooth_privileged=false
permissions/brick=false
permissions/broadcast_package_removed=false
permissions/broadcast_sms=false
permissions/broadcast_sticky=false
permissions/broadcast_wap_push=false
permissions/call_phone=false
permissions/call_privileged=false
permissions/camera=false
permissions/capture_audio_output=false
permissions/capture_secure_video_output=false
permissions/capture_video_output=false
permissions/change_component_enabled_state=false
permissions/change_configuration=false
permissions/change_network_state=false
permissions/change_wifi_multicast_state=false
permissions/change_wifi_state=false
permissions/clear_app_cache=false
permissions/clear_app_user_data=false
permissions/control_location_updates=false
permissions/delete_cache_files=false
permissions/delete_packages=false
permissions/device_power=false
permissions/diagnostic=false
permissions/disable_keyguard=false
permissions/dump=false
permissions/expand_status_bar=false
permissions/factory_test=false
permissions/flashlight=false
permissions/force_back=false
permissions/get_accounts=false
permissions/get_package_size=false
permissions/get_tasks=false
permissions/get_top_activity_info=false
permissions/global_search=false
permissions/hardware_test=false
permissions/inject_events=false
permissions/install_location_provider=false
permissions/install_packages=false
permissions/install_shortcut=false
permissions/internal_system_window=false
permissions/internet=false
permissions/kill_background_processes=false
permissions/location_hardware=false
permissions/manage_accounts=false
permissions/manage_app_tokens=false
permissions/manage_documents=false
permissions/manage_external_storage=false
permissions/master_clear=false
permissions/media_content_control=false
permissions/modify_audio_settings=false
permissions/modify_phone_state=false
permissions/mount_format_filesystems=false
permissions/mount_unmount_filesystems=false
permissions/nfc=false
permissions/persistent_activity=false
permissions/post_notifications=false
permissions/process_outgoing_calls=false
permissions/read_calendar=false
permissions/read_call_log=false
permissions/read_contacts=false
permissions/read_external_storage=false
permissions/read_frame_buffer=false
permissions/read_history_bookmarks=false
permissions/read_input_state=false
permissions/read_logs=false
permissions/read_media_audio=false
permissions/read_media_images=false
permissions/read_media_video=false
permissions/read_media_visual_user_selected=false
permissions/read_phone_state=false
permissions/read_profile=false
permissions/read_sms=false
permissions/read_social_stream=false
permissions/read_sync_settings=false
permissions/read_sync_stats=false
permissions/read_user_dictionary=false
permissions/reboot=false
permissions/receive_boot_completed=false
permissions/receive_mms=false
permissions/receive_sms=false
permissions/receive_wap_push=false
permissions/record_audio=false
permissions/reorder_tasks=false
permissions/restart_packages=false
permissions/send_respond_via_message=false
permissions/send_sms=false
permissions/set_activity_watcher=false
permissions/set_alarm=false
permissions/set_always_finish=false
permissions/set_animation_scale=false
permissions/set_debug_app=false
permissions/set_orientation=false
permissions/set_pointer_speed=false
permissions/set_preferred_applications=false
permissions/set_process_limit=false
permissions/set_time=false
permissions/set_time_zone=false
permissions/set_wallpaper=false
permissions/set_wallpaper_hints=false
permissions/signal_persistent_processes=false
permissions/status_bar=false
permissions/subscribed_feeds_read=false
permissions/subscribed_feeds_write=false
permissions/system_alert_window=false
permissions/transmit_ir=false
permissions/uninstall_shortcut=false
permissions/update_device_stats=false
permissions/use_credentials=false
permissions/use_sip=false
permissions/vibrate=false
permissions/wake_lock=false
permissions/write_apn_settings=false
permissions/write_calendar=false
permissions/write_call_log=false
permissions/write_contacts=false
permissions/write_external_storage=false
permissions/write_gservices=false
permissions/write_history_bookmarks=false
permissions/write_profile=false
permissions/write_secure_settings=false
permissions/write_settings=false
permissions/write_sms=false
permissions/write_social_stream=false
permissions/write_sync_settings=false
permissions/write_user_dictionary=false
xr_features/enable_khronos_plugin=false
khronos_xr_features/vendors=0
khronos_xr_features/htc/hand_tracking=0
khronos_xr_features/htc/tracker=0
khronos_xr_features/htc/eye_tracking=0
khronos_xr_features/htc/lip_expression=0
xr_features/enable_lynx_plugin=false
xr_features/enable_meta_plugin=false
meta_xr_features/eye_tracking=0
meta_xr_features/face_tracking=0
meta_xr_features/body_tracking=0
meta_xr_features/hand_tracking=0
meta_xr_features/hand_tracking_frequency=0
meta_xr_features/passthrough=0
meta_xr_features/render_model=0
meta_xr_features/use_anchor_api=false
meta_xr_features/use_anchor_sharing=false
meta_xr_features/use_scene_api=false
meta_xr_features/use_overlay_keyboard=false
meta_xr_features/use_experimental_features=false
meta_xr_features/boundary_mode=0
meta_xr_features/hybrid_app=0
meta_xr_features/quest_1_support=false
meta_xr_features/quest_2_support=true
meta_xr_features/quest_3_support=true
meta_xr_features/quest_pro_support=true
xr_features/enable_pico_plugin=true
pico_xr_features/eye_tracking=0
pico_xr_features/face_tracking=0
pico_xr_features/hand_tracking=0
xr_features/enable_magicleap_plugin=false
magicleap_xr_features/hand_tracking=0
pico_xr_features/hybrid_app=1
5 changes: 3 additions & 2 deletions samples/hybrid-app-sample/main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,10 @@ func _process(_delta: float) -> void:
panel_switcher_layer.update_pointer(t.origin, -t.basis.z, pointer_pressed)

func _on_right_controller_pointer_button_pressed(p_name: String) -> void:
if p_name == 'trigger_click':
print("button: ", p_name)
if p_name == 'trigger_click' or p_name == 'select_button':
pointer_pressed = true

func _on_right_controller_pointer_button_released(p_name: String) -> void:
if p_name == 'trigger_click':
if p_name == 'trigger_click' or p_name == 'select_button':
pointer_pressed = false

0 comments on commit f09e254

Please sign in to comment.