Jetpack Compose for XR

Declaratively build spatial UI layouts that take advantage of Android XR’s spatial capabilities.
Latest Update Stable Release Release Candidate Beta Release Alpha Release
May 7, 2025 - - - 1.0.0-alpha04

Declaring dependencies

To add a dependency on XR compose, you must add the Google Maven repository to your project. Read Google's Maven repository for more information.

Add the dependencies for the artifacts you need in the build.gradle file for your app or module:

Groovy

dependencies {
    implementation "androidx.xr.compose:compose:1.0.0-alpha04"

    // Use to write unit tests
    testImplementation "androidx.xr.compose:compose-testing:1.0.0-alpha04"
}

Kotlin

dependencies {
    implementation("androidx.xr.compose:compose:1.0.0-alpha04")

    // Use to write unit tests
    testImplementation("androidx.xr.compose:compose-testing:1.0.0-alpha04")
}

For more information about dependencies, see Add build dependencies.

Feedback

Your feedback helps make Jetpack better. Let us know if you discover new issues or have ideas for improving this library. Please take a look at the existing issues in this library before you create a new one. You can add your vote to an existing issue by clicking the star button.

Create a new issue

See the Issue Tracker documentation for more information.

Version 1.0

Version 1.0.0-alpha04

May 7, 2025

androidx.xr.compose:compose:1.0.0-alpha04 and androidx.xr.compose:compose-testing:1.0.0-alpha04 are released. Version 1.0.0-alpha04 contains these commits.

New Features

  • Added CompositionLocalConsumerSubspaceModifierNode interface to allow custom SubspaceModifier types to access composition local values.
  • Added a new SpatialPanel API that follows the compose AndroidView implementation style and deprecates the previous ViewBased SpatialPanel.
  • Added VolumeConstraints.Unbounded companion object which represents unbounded constraints.
  • Added SubspaceModifier.onPointSourceParams to allow a spatialized audio source.
  • A public ApplicationSubspace has been added, offering optional VolumeConstraints to define a 3D area where the app can render spatial content. By default, if no constraints are specified, the Subspace will be bounded by the SpatialUser's current field of view in width and height. Users can provide constraints to be used if the field of view cannot be determined. Otherwise, the default field of view width and height values are used.
  • Added SpatialExternalSurface, which can be used to render stereoscopic content. SpatialExternalSurface is customizable with modifiers (except alpha), and an edge feathering effect.
  • Added a new pointerHoverIcon Subspace Modifier that allows users to set the icon for the spatial pointer.

API Changes

  • Removed RequiresApi(34) restriction on all Jetpack XR packages. This restriction was redundant as Jetpack XR is currently only available on devices with API level 34+. (Iae0f8)
  • Projects released with Kotlin 2.0 require KGP 2.0.0 or newer to be consumed. (Idb6b5)
  • Back handling will now work on spatial panels without embedded activities. For back handling to work you need to specify android:enableOnBackInvokedCallback="true" in the android manifest.
  • Backhandling will now work on spatial dialogs. For backhandling to work you need to specify android:enableOnBackInvokedCallback="true" in the android manifest.
  • Compose-based and View-based SpatialPanels can now size themselves based on their contents.
  • Developers may now set their own custom SpatialElevationLevel values and are not limited to the predefined levels.
  • Orbiter elevation level may now be customized via the elevation parameter.
  • Subspace can now be bounded by the SpatialUser's field of view in width and height by default. If the field of view cannot be determined, the default field of view width and height values are used.
  • Added new callbacks onMoveStart and onMoveEnd to the Movable modifier. The onMoveStart and onMoveEnd callbacks are called when the user starts and ends moving a subspace composable with the movable modifier.
  • The name parameter has been removed from spatial APIs such as SpatialRow and SpatialPanel. For debugging spatial compose trees use SubspaceModifier.testTag instead.
  • Removed an unsupported overload of SpatialPopup that only has spatialElevationLevel and content. Please use the interface that supports onDimissRequest.
  • The onPoseChange callback from the Movable modifier has been removed. Use onMove instead.
  • SubspaceModifiers will no longer apply their effects if they are detached or currently detaching.
  • The existing SpatialRow API has been split into SpatialRow and SpatialCurvedRow. If previously using SpatialRow's curveRadius parameter, use SpatialCurvedRow now instead which offers the same behavior.
  • MainPanel and ActivityPanel no longer have title bars when run on a similarly recent system image.
  • Alpha and scale modifiers are now stackable and will multiply their values for the final applied alpha or scale value.
  • The onPoseChange callback from the Movable modifier has been optimized to perform smoother pose movement.
  • The movable and resizable modifiers will now perform their callbacks on the main thread to ensure that state changes will trigger recomposition.
  • Added state observation to the layout and measure phases to ensure that state changes in SubspaceLayout will trigger relayout.
  • Optimized modifier chain updates to better reuse existing modifiers.

Bug Fixes

  • Stopped scrimming when a SpatialDialog is shown. (Ic4594)
  • Relayout requests made while modifier nodes are detached will now be ignored.
  • Removed relayout phases triggered by Movable and Resizable modifiers.
  • Fixed a crash in MainPanel() composable that occurred when either dimension was set to zero, either directly or during a layout calculation, e.g., a SpatialRow/SpatialColumn calculation. The panel will now be hidden instead. Note that this fix specifically addresses crashes during the layout phase; resizing the panel to zero via user interaction will be handled separately. The hidden panel lacks UI affordances.
  • Fixed issue with maintainAspectRatio from the resizable modifier. The aspect ratio should be kept now.
  • Fixed an issue with nested Subspaces where they would be incorrectly positioned for a single frame.
  • Fixed issue where rounded corners were sometimes not applied when they should be.
  • NestedSubspaces will no longer appear for one frame in the wrong location.

Version 1.0.0-alpha03

February 26, 2025

androidx.xr.compose:compose:1.0.0-alpha03 and androidx.xr.compose:compose-testing:1.0.0-alpha03 are released with no notable changes since the last alpha. Version 1.0.0-alpha03 contains these commits

Version 1.0.0-alpha02

February 12, 2025

androidx.xr.compose:compose:1.0.0-alpha02 and androidx.xr.compose:compose-testing:1.0.0-alpha02 are released. Version 1.0.0-alpha02 contains these commits.

New Features

  • The Activity Panel can now scrim its content when a Spatial Dialog is activated.
  • The Orbiter API is now usable in SubspaceComposable contexts and will attach Orbiters to their nearest SubspaceLayout-based composable parent.
  • Introduced LayoutCoordinatesAwareModifierNode to allow custom positioning-based modifiers.
  • Added attach/detach lifecycle methods to SubspaceModifier.Node.
  • Added scaleWithDistance to the movable modifier. When scaleWithDistance is enabled, the subspace element moved will grow or shrink. It will also maintain any explicit scale that it had before movement.

API Changes

  • Removed SessionCallbackProvider in favor of SpatialCapabilities.

Other changes

  • Reduced minSDK to 24. All Jetpack XR APIs continue to require API 34 at runtime.
  • Orbiter EdgeOffset.inner, EdgeOffset.outer, and EdgeOffset.overlap constructors are no longer @Composable methods, which allows them to be used in non-composable contexts.
  • Update Spatial Elevation Levels to match the latest UX spec.
  • Implement SubspaceSemanticsInfo interface into MeasurableLayout.
  • Renamed SubspaceModifierElement to SubspaceModifierNodeElement.

Bug fixes

  • Fixes to stabilize SubspaceModifier ordering. SubspaceModifier should behave more reliably. Offset, rotate, scale, movable, and resizable modifier should now be usable in any order.

Version 1.0.0-alpha01

December 12, 2024

androidx.xr.compose:compose-*1.0.0-alpha01 is released.

Features of Initial Release

  • Initial developer release of Jetpack Compose for XR. Use familiar Compose concepts such as rows and columns to create spatial UI layouts in XR, whether you're porting an existing 2D app to XR or creating a new XR app from scratch. This library provides subspace and spatial composables: such as spatial panels and orbiters, which let you place your existing 2D Compose or Views-based UI in a spatial layout. It introduces the Volume subspace composable, which allows you to place SceneCore entities, such as 3D models, relative to your UI. Learn more in this developer guide:

    • Subspace: This composable can be placed anywhere within your app’s UI hierarchy, allowing you to maintain layouts for 2D and spatial UI without losing context between files. This makes it easier to share things like existing app architecture between XR and other form factors without needing to hoist state through your whole UI tree or re-architect your app.

    • SpatialPanel: A spatial panel is a subspace composable that lets you display app content–for example, you could display video playback, still images, or any other content in a spatial panel.

    • Orbiter: An orbiter is a spatial UI component. It's designed to be attached to a corresponding spatial panel, and contains navigation and contextual action items related to that spatial panel. For example, if you've created a spatial panel to display video content, you could add video playback controls inside an orbiter.

    • Volume: Place SceneCore entities, such as 3D models, relative to your UI.

  • Spatial Layout: You can create multiple spatial panels and place them within a Spatial Layout using SpatialRow, SpatialColumn, SpatialBox, and SpatialLayoutSpacer. Use SubspaceModifiers to customize your layout.

  • Spatial UI components: These elements can be reused in your 2D UI, and their spatial attributes will only be visible when spatial capabilities are enabled.

    • SpatialDialog: Panel will push slightly back in z-depth to display an elevated dialog.
    • SpatialPopUp: Panel will push slightly back in z-depth to display an elevated popup
    • SpatialElevation: SpatialElevationLevel can be set to add elevation.
  • SpatialCapabilities: Spatial capabilities can change as users interact with your app or the system, or can even be changed by your app itself—for example, moving into Home Space or Full Space. To avoid issues, your app needs to check for LocalSpatialCapabilities.current to determine which APIs are supported in the current environment. isSpatialUiEnabled: Spatial UI elements (e.g. SpatialPanel) isContent3dEnabled: 3D objects isAppEnvironmentEnabled: The environment isPassthroughControlEnabled: Whether or not the application can control the passthrough state isSpatialAudioEnabled: Spatial audio

Known Issues

  • Currently a minSDK of 30 is required to use Jetpack Compose for XR. As a workaround you may add the following manifest entry <uses-sdk tools:overrideLibrary="androidx.xr.scenecore, androidx.xr.compose"/> to be able to build and run with a minSDK of 23.
  • Jetpack XR apps currently require requesting android.permission.SCENE_UNDERSTANDING permission in the AndroidManifest.
  • When an app launches directly into Full Space using the PROPERTY_XR_ACTIVITY_START_MODE property in their manifest, Activities/Applications are initially opened in Home Space before transitioning into Full Space.
  • glTFs in Volume Composables may initially flicker at the wrong location.
  • Using a SpatialDialog in a panel that has been moved significantly will push the content in the wrong direction.