### Webhook Setup API Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This section details the process of setting up webhooks in the App Developer Dashboard, including configuring callback URLs, verification tokens, and subscribing to specific event fields. ```APIDOC ## Setting up Webhooks for your App ### Description Configure your application to receive real-time event notifications by setting up webhooks through the developer dashboard. This involves providing a callback URL, a verification token, and subscribing to desired event fields. ### Method POST ### Endpoint /webhooks ### Parameters #### Query Parameters - **access_token** (string) - Required - Your developer access token. #### Request Body - **callback_url** (string) - Required - The URL of your server endpoint that will receive webhook notifications. - **verify_token** (string) - Required - A custom string used to verify webhook requests. - **fields** (array of strings) - Required - A list of webhook fields to subscribe to (e.g., `["join_intent", "order_status"]`). - **include_values** (boolean) - Optional - If true, event notification payloads will include the names and new values of changed fields. ### Request Example ```json { "callback_url": "https://your-webhook-server.com/callback", "verify_token": "MY_SECRET_VERIFY_TOKEN", "fields": ["join_intent"], "include_values": true } ``` ### Response #### Success Response (200 OK) - **status** (string) - Indicates the success of the operation (e.g., "success"). - **webhook_id** (string) - The unique identifier for the created webhook subscription. #### Response Example ```json { "status": "success", "webhook_id": "wh_12345abcde" } ``` ``` -------------------------------- ### Example 'join_intent' Webhook Notification Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started An example of a 'join_intent' webhook notification. This event is triggered when a user accepts an in-game invitation or rejoins a multiplayer game session. It includes details about the joining user and the relevant session IDs. ```json { "entry": [ { "id": "345533925309564", "time": 1718052945, "changes": [ { "field": "join_intent", "value": { "destination_api_name": "destination_api_name", "joining_user": "10149999707612630", "lobby_session_id": "test_lobby_session_id", "match_session_id": "test_match_session_id" } } ] } ], "object": "application" } ``` -------------------------------- ### Track Subscription Starts with subscription_started Event Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started The 'subscription_started' event notifies your server when a user begins a subscription, whether it's new or a restart. This event provides details about the subscription, including owner ID, source app, and pricing terms. ```json { "entry": [ { "id": "345533925309564", "time": 1715797294, "changes": [ { "field": "subscription_started", "value": { "owner_id": "1234567890", "source_app": "TWILIGHT", "subscription": { "id": "1234567890", "trial_type": "TRIAL_OFFER", "sku": "bronzeTier0", "period_start_time": "1711956272", "period_end_time": "1711956272", "next_renewal_time": "1711956272", "is_active": true, "is_trial": false, "current_price_term": { "term": "MONTHLY", "price": "19.99", "currency": "USD" }, "next_price_term": { "term": "MONTHLY", "price": "1999.00", "currency": "USD" } } } } ] } ], "object": "application" } ``` -------------------------------- ### Base Webhook Notification Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started The fundamental structure of a webhook notification request sent from the platform to your server. It contains an array of entries, each representing a batch of events. ```APIDOC ## Base Webhook Notification Request Structure ### Description This is the base JSON structure for any webhook notification received by your server. It includes an `entry` array, where each object represents a distinct event or a batch of related events, along with an `object` type. ### Method POST ### Endpoint (Your configured Callback URL) ### Request Body - **entry** (array) - Required - An array containing webhook event entries. - **id** (string) - The ID of the entry. - **time** (number) - The Unix timestamp when the event occurred. - **changes** (array) - An array of webhook field events that occurred. - **field** (string) - The name of the webhook field that changed. - **value** (object) - The value associated with the changed field. - **object** (string) - Required - The type of object the webhook relates to (e.g., "application"). ### Request Example ```json { "entry": [ { "id": "345533925309564", "time": 1718052945, "changes": [ { "field": "join_intent", "value": { "destination_api_name": "destination_api_name", "joining_user": "10149999707612630", "lobby_session_id": "test_lobby_session_id", "match_session_id": "test_match_session_id" } } ] } ], "object": "application" } ``` ``` -------------------------------- ### Join Intent Webhook Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started Details the structure and purpose of the 'join_intent' webhook, which notifies your server when a user accepts an in-game invitation or rejoins a multiplayer game session. ```APIDOC ## Multiplayer Join Intent Webhook (`join_intent`) ### Description This webhook is triggered when a user accepts an in-game invitation or rejoins a multiplayer game session. It provides information necessary for server-side logic, such as reserving lobby slots or anticipating new players. ### Method POST ### Endpoint (Your configured Callback URL) ### Parameters #### Request Body (within `changes` array) - **field** (string) - Must be `"join_intent"`. - **value** (object) - Contains details about the join intent. - **destination_api_name** (string) - API name of the destination the user is intending to join. - **joining_user** (string) - ID of the user who is joining. - **lobby_session_id** (string) - Lobby session ID that the user intends to join. - **match_session_id** (string) - Match session ID that the user intends to join. ### Request Example ```json { "entry": [ { "id": "345533925309564", "time": 1718052945, "changes": [ { "field": "join_intent", "value": { "destination_api_name": "destination_api_name", "joining_user": "10149999707612630", "lobby_session_id": "test_lobby_session_id", "match_session_id": "test_match_session_id" } } ] } ], "object": "application" } ``` ### Response #### Success Response (200 OK) An empty response or a simple acknowledgement (e.g., `{ "status": "received" }`) is expected to confirm receipt of the webhook. #### Response Example ```json { "status": "received" } ``` ``` -------------------------------- ### Track Add-On Purchases with order_status Event Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started The 'order_status' event is triggered when a user purchases or updates an add-on. Use this to track new purchases and refunds for your application. It includes details like event time, user ID, and product information. ```json { "entry": { "id": "345533925309564", "time": 1718052945, "changes": [ { "field": "order_status", "value": { "event_time": "1659742639", "user_id": "10149999707612630", "product_info": { "notification_type": "PURCHASED", "reporting_id": "03f8833e-9c02-4fa0-978f-4cfe91f86bae", "sku": "item_sku_1", "developer_payload": "{\"quoteId\": 1234567}" } } } ] } } ``` -------------------------------- ### Handle Subscription Uncanceled Webhook Event Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This event is sent to your server when a user reactivates their subscription before its expiration date. It provides details about the owner and the subscription, allowing you to update the user's active status accordingly. ```json { "entry": [ { "id": "345533925309564", "time": 1717714175, "changes": [ { "value": { "owner_id": "7663588487057119", "subscription": { "id": "228e599134540916c63a33cd6aa485379deb3a959ba4075f323b31bb1dda7ecc", "sku": "bronze_test_01", "period_start_time": "1717713920", "period_end_time": "1720305920", "next_renewal_time": "1720305920", "is_active": true, "is_trial": false, "current_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" }, "next_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" } } }, "field": "subscription_uncanceled" } ] } ], "object": "application" } ``` -------------------------------- ### Gradle: Kotlin DSL Build Configuration Example Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-template-walkthrough This is an example of a `build.gradle.kts` file, likely for an Android application module, showcasing how to configure the build with the Spatial SDK. It includes dependencies required for spatial development. ```kotlin plugins { id("com.android.application") id("org.jetbrains.kotlin.android") } android { namespace = "com.example.spatialapp" compileSdk = 33 defaultConfig { applicationId = "com.example.spatialapp" minSdk = 29 targetSdk = 33 versionCode = 1 versionName = "1.0" } // ... other configurations } dependencies { // Spatial SDK core package implementation("com.meta.spatial.sdk:meta-spatial-sdk:1.0.0") // VR-specific features implementation("com.meta.spatial.sdk:meta-spatial-sdk-vr:1.0.0") // Toolkit for common components implementation("com.meta.spatial.sdk:meta-spatial-sdk-toolkit:1.0.0") // Other standard Android dependencies implementation("androidx.core:core-ktx:1.10.1") implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1") implementation("androidx.activity:activity-compose:1.7.0") implementation(platform("androidx.compose:compose-bom:2023.03.00")) implementation("androidx.compose.ui:ui") implementation("androidx.compose.ui:ui-graphics") implementation("androidx.compose.ui:ui-tooling-preview") implementation("androidx.compose.material3:material3") // ... other dependencies } ``` -------------------------------- ### Handle Subscription Canceled Webhook Event Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This event notifies your server when a user cancels their subscription. The payload contains information about the owner, subscription details, and the reason for cancellation. It's important to process this event to update user statuses and manage your subscription base. ```json { "entry": [ { "id": "345533925309564", "time": 1717714215, "changes": [ { "value": { "owner_id": "7663588487057119", "subscription": { "id": "228e599134540916c63a33cd6aa485379deb3a959ba4075f323b31bb1dda7ecc", "sku": "bronze_test_01", "period_start_time": "1717714180", "period_end_time": "1720306180", "next_renewal_time": "1720306180", "is_active": true, "is_trial": false, "current_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" }, "next_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" } }, "cancel_reason": "PRICE_TOO_EXPENSIVE" }, "field": "subscription_canceled" } ] } ], "object": "application" } ``` -------------------------------- ### Base Webhook Notification Request Structure Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This is the base JSON structure for a webhook notification request. It includes an 'entry' array containing event details like ID, timestamp, and changes, along with the 'object' type. ```json { "entry": [ { "id": string, "time": number (Unix Timestamp), "changes": Array } ], "object": "application" } ``` -------------------------------- ### Example Request for Subscription Status - cURL Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-subscriptions-s2s An example cURL command to fetch detailed subscription data, including price terms and renewal information. This demonstrates how to construct a request with various parameters and access tokens. ```shell curl -d "access_token=OC|$APP_ID|$APP_SECRET" -d "fields=id,sku,owner{id},is_active,is_trial,trial_type,cancellation_time,period_start_time,period_end_time,next_renewal_time,current_price_term{term,currency,price},next_price_term{term,currency,price}" -G https://graph.oculus.com/application/subscriptions ``` -------------------------------- ### Create Challenge Request Example Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-challenges-s2s An example of the HTTP POST request structure for creating a challenge. This includes the endpoint, required query parameters such as leaderboard API name, creation type, visibility, and title. It also shows the necessary host and authorization headers. ```http POST /1234757621998335/challenges/?api_name=leaderboard_api_name=hello_friends&creation_type=DEVELOPER_CREATED&visibility=PRIVATE&title=sample_challenge Host: graph.oculus.com Authorization: Bearer OC|1234f7a788b0c0b270f9691d0a06d5a5 ``` -------------------------------- ### Handle Subscription Renewal Success Webhook Event Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This event is triggered on your server when a user's subscription is successfully renewed. It's crucial to ensure your server can handle potentially high volumes of these events, as they correlate with the number of active subscriptions. The payload includes details about the owner, subscription ID, SKU, and renewal periods. ```json { "entry": [ { "id": "345533925309564", "time": 1715796778, "changes": [ { "field": "subscription_renewal_success", "value": { "owner_id": "1234567890", "subscription": { "id": "1234567890", "sku": "bronzeTier0", "period_start_time": "1711956272", "period_end_time": "1711956272", "next_renewal_time": "1711956272", "is_active": true, "is_trial": false, "current_offer": { "term": "MONTHLY", "price": "19.99", "currency": "USD" }, "next_offer": { "term": "MONTHLY", "price": "19.99", "currency": "USD" } } } } ] } ], "object": "application" } ``` -------------------------------- ### Example Attestation Token Claims (JSON) Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-attestation-api This snippet shows an example of the JSON claims obtained after Base64URL decoding a verified attestation token. It includes details about the request, application state, and device state. ```json { "request_details": { "exp": 1684606153, "nonce": "JMxMPp1H6kCxGzPRsjKFLw==", "timestamp": 1684519753 }, "app_state": { "app_integrity_state": "NotEvaluated", "package_cert_sha256_digest": [ "c8a2e9bccf597c2fb6dc66bee293fc13f2fc47ec77bc6b2b0d52c11f51192ab8" ], "package_id": "com.example.name123", "version": "1" }, "device_state": { "device_integrity_state": "NotTrusted", "unique_id": "cd81cd7e7e0525f99442ab6392117e89759e8872852de0495aa58f22bd8a1253" } } ``` -------------------------------- ### Example Subscription Data Structure Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-subscriptions-s2s An example JSON object representing subscription data, including details like ID, SKU, pricing, and active status. This data is primarily for troubleshooting. ```json { "data": [ { "id": "1231b2c3d4e5f6g7h8i9j0", "sku": "OPTIONAL_SUBSCRIPTION", "owner": { "id": "3559884437424131" }, "current_price_term": { "price": "1.99", "term": "MONTHLY", "currency": "USD" }, "next_price_term": { "price": "1.99", "term": "MONTHLY", "currency": "USD" }, "is_active": false, "is_trial": false, "period_start_time": "2021-03-09T13:04:20+0000", "period_end_time": "2021-03-09T13:04:20+0000", "next_renewal_time": "2021-03-09T13:04:20+0000" } ], "paging": { "cursors": { "before": "QVFIUlliZAnlkTEVnUkFkVTBJZAW9lMWprR0dkaGtuQjhTT0lTdzRiTEo1dkstSXoybDVRWEFFUzA0RURfQjVMMUxXZAzJ4VENTV1RadU9uejFaUmlIUlo4cUlR", "after": "QVFIUlZAGTmllREUwcWdJRkhGcUtBWXZA2WWFvSkJHMlJ1dnpfVVRLU2ZAPNHc1MjVCbXc0d3YyWi1meU1DNjhQWTBJaldrcDIxVkpxNWZAMSmNfa2lOcldVTUhB" } } } ``` -------------------------------- ### Subscription Expired Event JSON Payload Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-webhooks-getting-started This JSON object represents the structure of the `subscription_expired` webhook event. It contains details about the subscription, including owner ID, expiration time, and pricing. This event is crucial for tracking canceled subscriptions and managing server load. ```json { "entry": [ { "id": "345533925309564", "time": 1717714227, "changes": [ { "value": { "owner_id": "7663588487057119", "subscription": { "id": "228e599134540916c63a33cd6aa485379deb3a959ba4075f323b31bb1dda7ecc", "sku": "bronze_test_01", "period_start_time": "1717714180", "period_end_time": "1717714221", "next_renewal_time": "1717714221", "is_active": false, "is_trial": false, "current_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" }, "next_price_term": { "term": "MONTHLY", "price": "1.99", "currency": "USD" } } }, "field": "subscription_expired" } ] } ], "object": "application" } ``` -------------------------------- ### Custom Fragment Shader Example Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-custom-shaders An example of a fragment shader file (`.frag`) for the Meta Spatial SDK. It sets up the required version and extensions and includes a base fragment shader from the SDK. The `main` function is implemented to output a solid red color. ```c #version 400 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable #include void main() { // simply write out a red color outColor = vec4(1.0f, 0.0f, 0.0f, 1.0f); } ``` -------------------------------- ### Java Example: Getting App's Cache Directory Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-cloud-backup This Java code snippet illustrates how to get the path to the app's cache directory using `getCacheDir()`. Files in this directory are typically excluded from Android Auto Backup. ```java File cacheDir = context.getCacheDir(); // The 'cacheDir' variable now holds the path to the cache directory. ``` -------------------------------- ### Java Example: Getting App's No Backup Files Directory Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-cloud-backup This Java code snippet demonstrates how to access the directory specifically designated for files that should not be backed up using `getNoBackupFilesDir()`. This is useful for temporary or sensitive data. ```java File noBackupDir = context.getNoBackupFilesDir(); // The 'noBackupDir' variable now holds the path to the no-backup files directory. ``` -------------------------------- ### Using the Scene class API Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-scene This section provides an example of how to use the Scene class to set up a basic immersive scene, including configuring lighting, reference space, viewer position, and loading GLXF compositions. ```APIDOC ## Scene Class Setup Example ### Description Demonstrates the setup of an immersive scene using various `Scene` class features in Meta Spatial SDK. ### Method `override fun onSceneReady()` ### Endpoint N/A (part of the SDK's scene lifecycle) ### Parameters None directly for the `onSceneReady` method call, but it utilizes the `scene` object. ### Request Body N/A ### Request Example ```kotlin override fun onSceneReady() { super.onSceneReady() // 1. Set reference space to enable recentering scene.setReferenceSpace(ReferenceSpace.LOCAL_FLOOR) // 2. Configure scene lighting with ambient, sun color, and direction scene.setLightingEnvironment( ambientColor = Vector3(0f), sunColor = Vector3(7.0f, 7.0f, 7.0f), sunDirection = -Vector3(1.0f, 3.0f, -2.0f), environmentIntensity = 0.3f, ) // 3. Update environment with Image Based Lighting scene.updateIBLEnvironment("environment.env") // 4. Set initial viewer position and orientation scene.setViewOrigin(0.0f, 0.0f, 2.0f, 180.0f) // 5. Create a skybox with custom texture Entity.create( listOf( Mesh(Uri.parse("mesh://skybox"), hittable = MeshCollision.NoCollision), Material().apply { baseTextureAndroidResourceId = R.drawable.skydome unlit = true // Prevent scene lighting from affecting the skybox }, Transform(Pose(Vector3(x = 0f, y = 0f, z = 0f))), ) ) // 6. Load GLXF scene composition loadGLXF { composition -> val environmentEntity: Entity? = composition.getNodeByName("Environment").entity val environmentMesh = environmentEntity?.getComponent() environmentMesh?.defaultShaderOverride = SceneMaterial.UNLIT_SHADER environmentEntity?.setComponent(environmentMesh!!) } } // Helper function to load GLXF scene composition private fun loadGLXF(onLoaded: ((GLXFInfo) -> Unit) = {}): Job { gltfxEntity = Entity.create() return activityScope.launch { glXFManager.inflateGLXF( Uri.parse("apk:///scenes/Composition.glxf"), rootEntity = gltfxEntity!!, onLoaded = onLoaded, ) } } ``` ### Response N/A (This is a setup function within the application lifecycle) ### Response Example N/A ``` -------------------------------- ### Challenge Creation Response Example Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-challenges-s2s A sample JSON response received after successfully creating a challenge. This response includes the unique ID of the created challenge, its title, start date, end date, and details about the associated leaderboard. ```json { "id": "2643098232993236", "title": "hello_challenge", "start_date": "2020-07-14T22:58:24+0000", "end_date": "2020-07-17T22:58:24+0000", "leaderboard": { "id": "3123283331082599" } } ``` -------------------------------- ### Kotlin: Main VR Activity Example Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-template-walkthrough This snippet shows the structure of a Kotlin file for the main VR activity in a spatial application. It's responsible for setting up the 3D environment, managing user position, and handling immersive spatial experiences. ```kotlin package com.example.spatialapp import com.oculus.spatial.core.ImmersiveActivity import android.os.Bundle class ImmersiveActivity : ImmersiveActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize your 3D environment here // Set up user positioning and spatial interactions } } ``` -------------------------------- ### Create or Update Leaderboard Entry (cURL) Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-leaderboards-s2s Demonstrates creating or updating a leaderboard entry using cURL. This example shows a client-authoritative setup which requires a user access token. ```curl curl -d "access_token=" -d "api_name=best_leaderboard" -d "score=12345" -d "extra_data_base64=T271bHVz" -d "force_update=true" https://graph.oculus.com/leaderboard_submit_entry ``` -------------------------------- ### Spatial SDK Initialization and Component Registration in onCreate Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-activity-lifecycle This snippet demonstrates the `onCreate` method for initializing the Spatial SDK, registering custom components and systems, and loading GLXF resources. It's crucial to call `super.onCreate()` first. Dependencies include `componentManager`, `systemManager`, and `loadGLXF`. ```kotlin override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Important: Always call super.onCreate() first // Register components componentManager.registerComponent(MyCustomComponent.Companion) // Register systems systemManager.registerSystem(MyCustomSystem()) // Load resources loadGLXF { composition -> // Handle loaded 3D models val environmentEntity = composition.getNodeByName("environment").entity // Configure entity components } } ``` -------------------------------- ### Java Example: Getting App's External Files Directory Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-cloud-backup This Java code snippet shows how to retrieve the path to the app-specific directory on external storage using `getExternalFilesDir()`. Files in this location are generally included in Android Auto Backup. ```java File externalFilesDir = context.getExternalFilesDir(null); // Pass null or a subdirectory name // The 'externalFilesDir' variable now holds the path to the external app-specific files directory. ``` -------------------------------- ### Manage VR Scene with Spatial SDK (Kotlin) Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-vr-basics This Kotlin code sample utilizes the Meta Spatial SDK's Scene API to manage the VR environment. It demonstrates setting the reference space, checking passthrough mode, positioning the view origin, and updating environment lighting. This is useful for initializing and configuring the VR scene. Dependencies include AppSystemActivity, Scene, ReferenceSpace, and Log. ```kotlin class MyActivity : AppSystemActivity() { override fun onSceneReady() { super.onSceneReady() // Set the reference space for tracking scene.setReferenceSpace(ReferenceSpace.LOCAL_FLOOR) // Enable/disable passthrough for MR mode val isMrMode = scene.isSystemPassthroughEnabled() // Set view origin position scene.setViewOrigin(0f, 0.0f, 2.0f, 0.0f) // Update environment lighting scene.updateIBLEnvironment("chromatic.env") } } ``` -------------------------------- ### Manually Configure Direct-to-Surface Rendering in Kotlin Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-media-playback This Kotlin code sample shows how to manually set up direct-to-surface rendering, which requires direct-to-compositor as a prerequisite. It configures the panel, sets up ExoPlayer, and connects it directly to the panel surface, bypassing the Android UI pipeline for improved video rendering performance. ```kotlin private fun createDirectToSurfacePanel( panelConfigBlock: PanelConfigOptions.() -> Unit, mediaItem: MediaItem, ) { // Create entity entity = Entity.create( Transform(), Hittable(hittable = MeshCollision.LineTest), ) val panelConfigOptions = PanelConfigOptions().apply(panelConfigBlock) // Enable Direct-To-Compositor prerequisites panelConfigOptions.apply { mips = 1 forceSceneTexture = false enableTransparent = false } SpatialActivityManager.executeOnVrActivity { immersiveActivity -> // Create PanelSceneObject with custom configs val panelSceneObject = PanelSceneObject(immersiveActivity.scene, entity, panelConfigOptions) // Assign PanelSceneObject to entity immersiveActivity.systemManager .findSystem() .addSceneObject( entity, CompletableFuture().apply { complete(panelSceneObject) }) // Set up ExoPlayer exoPlayer.setMediaItem(mediaItem) exoPlayer.prepare() // Connect ExoPlayer directly to panel surface exoPlayer.setVideoSurface(panelSceneObject.getSurface()) } } ``` -------------------------------- ### Java Example: Getting App's Internal Files Directory Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-cloud-backup This Java code snippet demonstrates how to obtain the path to the internal files directory of an Android application using the `getFilesDir()` method available through a Context object. This directory is typically included in auto backups. ```java File filesDir = context.getFilesDir(); // The 'filesDir' variable now holds the path to the internal files directory. ``` -------------------------------- ### Match Panel Resolution to Video Content Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-media-playback Illustrates how to match the panel's display resolution to the video content's resolution for optimal quality and performance, using a 1080p video as an example. ```kotlin MediaPanelSettings( display = PixelDisplayOptions(width = 1920, height = 1080), // ... ) ``` -------------------------------- ### Example Entity Setup for Tree Structure Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-childrenof-query This Kotlin code demonstrates how to create and set up `Entity` objects with `TreeNode` components to represent a hierarchical tree structure. It shows the creation of entities and assigning parent-child relationships using `Entity.nullEntity()` for root nodes and references to parent entities for children. ```kotlin /** * * A * / \ * B C * / \ \ * D E F */ val A = Entity.create() val B = Entity.create() val C = Entity.create() val D = Entity.create() val E = Entity.create() val F = Entity.create() A.setComponent(TreeNode(parent = Entity.nullEntity(), name = "A")) B.setComponent(TreeNode(parent = A, name = "B")) C.setComponent(TreeNode(parent = A, name = "C")) D.setComponent(TreeNode(parent = B, name = "D")) E.setComponent(TreeNode(parent = B, name = "E")) F.setComponent(TreeNode(parent = C, name = "F")) ``` -------------------------------- ### Initialize Platform SDK and Check Entitlements Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-managed-account-info Initializes the Platform SDK and verifies if the current user is entitled to the application. This is a prerequisite for accessing user-specific information and functionalities. ```csharp Core.AsyncInitialize().OnComplete(...); Entitlements.IsUserEntitledToApplication().OnComplete(...); ``` -------------------------------- ### Kotlin: Advanced Panel Registration with PanelCreator Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-2dpanel-registration Demonstrates advanced panel registration using PanelCreator in Kotlin. It shows how to initialize PanelCreator with a registration ID and a lambda function that generates a PanelSceneObject. The example highlights starting with basic UIPanelSettings, converting them to PanelConfigOptions, and then applying custom properties like mips, effectShader, and a custom sceneMeshCreator for specialized geometry. ```kotlin import com.meta.spatial.toolkit.PanelCreator import com.meta.spatial.toolkit.PanelRegistration PanelCreator( registrationId = R.id.custom_panel, panelCreator = { entity -> // Start with Panel Settings for basic configuration val baseSettings = UIPanelSettings( shape = QuadShapeOptions(width = 2f, height = 1.5f), display = DpDisplayOptions(width = 800f, height = 600f) ) // Convert to PanelConfigOptions and customize further val options = baseSettings.toPanelConfigOptions().apply { // Access properties not available through UIPanelSettings // Here are a few examples of the many things you can set mips = 8 // Custom mip levels effectShader = "data/shaders/custom/gammaCorrection.frag" // Custom effect shader // Custom mesh creator for specialized geometry sceneMeshCreator = { texture -> // Create custom mesh geometry createCustomPanelMesh(texture, entity) } } // Create the panel with custom options PanelSceneObject( scene, spatialContext, R.layout.my_custom_layout, entity, options ) } ) ``` -------------------------------- ### Spatial Scene Setup and Entity Creation in onSceneReady Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-activity-lifecycle This snippet shows the `onSceneReady` callback, ideal for configuring the scene environment, lighting, reference space, and creating scene entities. It's called after the scene is loaded and on the first `onResume()`. Ensure `super.onSceneReady()` is called first. This method uses Spatial SDK APIs for scene manipulation and entity creation. ```kotlin override fun onSceneReady() { super.onSceneReady() // Important: Always call super.onSceneReady() first // Set the reference space for tracking scene.setReferenceSpace(ReferenceSpace.LOCAL_FLOOR) // Configure lighting scene.setLightingEnvironment( ambientColor = Vector3(0f), sunColor = Vector3(7.0f, 7.0f, 7.0f), sunDirection = -Vector3(1.0f, 3.0f, -2.0f), environmentIntensity = 0.3f ) // Set environment map scene.updateIBLEnvironment("environment.env") // Set the view origin scene.setViewOrigin(0.0f, 0.0f, 0.0f, 0.0f) // Create entities in the scene Entity.create( listOf( Mesh(Uri.parse("mesh://skybox"), hittable = MeshCollision.NoCollision), Material().apply { baseTextureAndroidResourceId = R.drawable.skydome unlit = true }, Transform(Pose(Vector3(x = 0f, y = 0f, z = 0f))) ) ) } ``` -------------------------------- ### Install APK using ADB Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ts-adb Installs an Android application package (APK) file onto a connected device. The `-r` option allows for overwriting an existing installation. ```bash adb install ``` ```bash adb install -r C:\\Dev\\Android\\MyProject\\VrApp.apk ``` -------------------------------- ### Configure Immersive Scene with Kotlin Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-scene Sets up a basic immersive scene by configuring the reference space, lighting, environment, viewer position, adding a skybox, and loading a GLXF scene composition. This example demonstrates a typical workflow for creating a cohesive immersive experience using the Scene class API. ```kotlin override fun onSceneReady() { super.onSceneReady() // 1. Set reference space to enable recentering scene.setReferenceSpace(ReferenceSpace.LOCAL_FLOOR) // 2. Configure scene lighting with ambient, sun color, and direction scene.setLightingEnvironment( ambientColor = Vector3(0f), sunColor = Vector3(7.0f, 7.0f, 7.0f), sunDirection = -Vector3(1.0f, 3.0f, -2.0f), environmentIntensity = 0.3f, ) // 3. Update environment with Image Based Lighting scene.updateIBLEnvironment("environment.env") // 4. Set initial viewer position and orientation scene.setViewOrigin(0.0f, 0.0f, 2.0f, 180.0f) // 5. Create a skybox with custom texture Entity.create( listOf( Mesh(Uri.parse("mesh://skybox"), hittable = MeshCollision.NoCollision), Material().apply { baseTextureAndroidResourceId = R.drawable.skydome unlit = true // Prevent scene lighting from affecting the skybox }, Transform(Pose(Vector3(x = 0f, y = 0f, z = 0f))), ) ) // 6. Load GLXF scene composition // wait for GLXF to load before accessing nodes inside it loadGLXF { composition -> // get the environment mesh from Spatial Editor and set it to use an unlit shader. val environmentEntity: Entity? = composition.getNodeByName("Environment").entity val environmentMesh = environmentEntity?.getComponent() environmentMesh?.defaultShaderOverride = SceneMaterial.UNLIT_SHADER environmentEntity?.setComponent(environmentMesh!!) } } // Load GLXF scene composition from assets private fun loadGLXF(onLoaded: ((GLXFInfo) -> Unit) = {}): Job { gltfxEntity = Entity.create() return activityScope.launch { glXFManager.inflateGLXF( Uri.parse("apk:///scenes/Composition.glxf"), rootEntity = gltfxEntity!!, onLoaded = onLoaded, ) } } ``` -------------------------------- ### Kotlin: Transition to Panel Activity in Home Environment Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/hybrid-apps-overview Launches a panel activity within the user's Home environment. This involves creating an `Intent` for the panel activity, wrapping it in a `PendingIntent`, and then launching the Home environment with this `PendingIntent` as an extra. ```kotlin fun launchPanelActivityInHome() { Log.d(TAG, "Setting up panel Activity pending intent") val context = context?.applicationContext ?: return // Create the intent used to launch the Panel Activity val panelIntent = Intent(context, PanelActivity::class.java).apply { action = Intent.ACTION_MAIN addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) } // Wrap the Panel Intent inside of a PendingIntent object val pendingPanelIntent = PendingIntent.getActivity( context, 0, panelIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE) // Create an Intent to launch the Home environment, providing the PendingIntent object as extra parameters Log.d(TAG, "Launching Home") val homeIntent = Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .putExtra("extra_launch_in_home_pending_intent", pendingPanelIntent) startActivity(homeIntent) } ``` -------------------------------- ### Kotlin - Tip Screen Implementations Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-scanner-overview Contains implementations for various tip screens, such as FindObjectsScreen, HelpScreen, NoObjectsDetectedScreen, and SelectObjectTipScreen. These are displayed to users to provide context-sensitive help and guidance. ```kotlin views/tips/FindObjectsScreen.kt views/tips/HelpScreen.kt views/tips/NoObjectsDetectedScreen.kt views/tips/SelectObjectTipScreen.kt ``` -------------------------------- ### Get User Age Category - Android SDK Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-get-age-category-api This code snippet demonstrates how to retrieve the age category of the currently logged-in user using the Get Age Category API in a Meta Quest Android application. It requires a minimum SDK build version of 56.0 and does not take any parameters. The API returns a JSON object with the user's age category (CH, TN, AD, or UNKNOWN). ```java // Get the age category of the currently logged-in user. import com.meta.horizon.platform.ovr.requests.UserAgeCategory; UserAgeCategory.get() ``` -------------------------------- ### Configure Video Playback with VideoSurfacePanelRegistration (Kotlin) Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-media-playback Sets up high-performance video playback using VideoSurfacePanelRegistration, rendering directly to the surface for maximum performance and DRM support. It requires ExoPlayer setup and MediaPanelSettings. ```kotlin VideoSurfacePanelRegistration( R.id.video_panel, surfaceConsumer = { entity, surface -> // ExoPlayer setup val exoPlayer = ExoPlayer.Builder(this).build().apply { setVideoSurface(surface) setMediaItem(mediaItem) prepare() } }, settingsCreator = { entity -> MediaPanelSettings( shape = QuadShapeOptions(width = 1.6f, height = 0.9f), display = PixelDisplayOptions(width = 1920, height = 1080), rendering = MediaPanelRenderOptions( stereoMode = StereoMode.LeftRight, isDRM = true ) ) } ) ``` -------------------------------- ### Example of Custom Exclusion Path in Meta Quest Dashboard Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/ps-cloud-backup This example shows how a custom file path would be specified in the Meta Quest Dashboard for exclusion from Android Auto Backup. The path is relative to the app's internal or external files directories. ```plaintext UE4Game/SomeGame/SomeGame/BigFiles/SomeFile.txt ``` -------------------------------- ### Switching Object Detector Implementations Source: https://developers.meta.com/horizon/llmstxt/documentation/spatial-sdk/spatial-sdk-scanner-ot Demonstrates how to switch between different object detector implementations (ML Kit, MediaPipe, OpenCV) by uncommenting or commenting lines of code. This allows for easy testing and comparison of various object detection technologies within the application. ```kotlin // different options for object detection; though only MLKit currently supports persistent ids //objectDetector = MediaPipeObjectDetector(activity) objectDetector = MLKitObjectDetector(activity) //objectDetector = OpenCVObjectDetector(activity) ```