From b3c0922ea88c5b0c644b39ab16c1cfc4534bc16b Mon Sep 17 00:00:00 2001 From: Tram Bui Date: Thu, 9 Jul 2026 12:20:12 -0700 Subject: [PATCH 1/3] uncomment snapshot build id --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 0346ade7c..aa8e38725 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,4 +26,4 @@ android.enableR8.fullMode=true # Use an AndroidX snapshot build. # https://androidx.dev/snapshots/builds -# snapshotVersion=14793336 + snapshotVersion=15770982 From f617478f8447b032ac64e717271e118856623c27 Mon Sep 17 00:00:00 2001 From: Tram Bui Date: Thu, 9 Jul 2026 14:26:04 -0700 Subject: [PATCH 2/3] migrations for snapshot version --- .../main/java/com/example/xr/arcore/Anchors.kt | 4 ++-- .../main/java/com/example/xr/arcore/DepthMaps.kt | 2 -- xr/src/main/java/com/example/xr/arcore/Hands.kt | 9 ++++++--- .../main/java/com/example/xr/compose/Orbiter.kt | 7 +++---- .../com/example/xr/compose/SceneCoreEntity.kt | 11 +++++------ .../com/example/xr/compose/SpatialGltfModel.kt | 4 +++- .../java/com/example/xr/compose/SpatialPanel.kt | 10 ++++++---- .../java/com/example/xr/glimmer/CardSamples.kt | 3 ++- .../xr/projected/ProjectedMainActivity.kt | 8 +++++--- .../com/example/xr/runtime/DeviceLifecycle.kt | 2 -- .../com/example/xr/runtime/DisplayBlendMode.kt | 2 -- .../main/java/com/example/xr/runtime/Session.kt | 16 ++++++++++------ .../java/com/example/xr/scenecore/GltfEntity.kt | 4 +++- 13 files changed, 45 insertions(+), 37 deletions(-) diff --git a/xr/src/main/java/com/example/xr/arcore/Anchors.kt b/xr/src/main/java/com/example/xr/arcore/Anchors.kt index d1c22df91..5c6893f79 100644 --- a/xr/src/main/java/com/example/xr/arcore/Anchors.kt +++ b/xr/src/main/java/com/example/xr/arcore/Anchors.kt @@ -23,7 +23,7 @@ import androidx.xr.runtime.Config import androidx.xr.runtime.Session import androidx.xr.runtime.SessionConfigureSuccess import androidx.xr.runtime.math.Pose -import androidx.xr.scenecore.AnchorEntity +import androidx.xr.scenecore.AnchorSpace import androidx.xr.scenecore.Entity import androidx.xr.scenecore.scene @@ -59,7 +59,7 @@ private fun attachEntityToAnchor( anchor: Anchor ) { // [START androidxr_arcore_entity_tracks_anchor] - AnchorEntity.create(session, anchor).apply { + AnchorSpace.create(session, anchor).apply { parent = session.scene.activitySpace addChild(entity) } diff --git a/xr/src/main/java/com/example/xr/arcore/DepthMaps.kt b/xr/src/main/java/com/example/xr/arcore/DepthMaps.kt index 76e0161db..6ee4af88a 100644 --- a/xr/src/main/java/com/example/xr/arcore/DepthMaps.kt +++ b/xr/src/main/java/com/example/xr/arcore/DepthMaps.kt @@ -20,7 +20,6 @@ import android.content.Context import androidx.xr.arcore.Depth import androidx.xr.runtime.Config import androidx.xr.runtime.DepthEstimationMode -import androidx.xr.runtime.ExperimentalXrDeviceLifecycleApi import androidx.xr.runtime.RenderingMode import androidx.xr.runtime.Session import androidx.xr.runtime.SessionConfigureSuccess @@ -39,7 +38,6 @@ private fun configureDepthEstimation(session: Session) { // [END androidxr_arcore_depthmaps_configure] } -@OptIn(ExperimentalXrDeviceLifecycleApi::class) private fun checkLeftDepthSupport(context: Context) { // [START androidxr_arcore_depthmaps_check_support] val xrDevice = XrDevice.getCurrentDevice(context) diff --git a/xr/src/main/java/com/example/xr/arcore/Hands.kt b/xr/src/main/java/com/example/xr/arcore/Hands.kt index 2c6e4c9e3..97f8ba1cb 100644 --- a/xr/src/main/java/com/example/xr/arcore/Hands.kt +++ b/xr/src/main/java/com/example/xr/arcore/Hands.kt @@ -17,6 +17,7 @@ package com.example.xr.arcore import android.app.Activity +import android.content.Context import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -151,10 +152,12 @@ class GenerateHandJointData : ComponentActivity() { @OptIn(FlowPreview::class) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - val session = (Session.create(context = this) as SessionCreateSuccess).session - val config = Config.Builder(session.config).setHandTracking(HandTrackingMode.BOTH).build() - session.configure(config) + lifecycleScope.launch { + val session = (Session.create(context = this as Context) as SessionCreateSuccess).session + val config = Config.Builder(session.config).setHandTracking(HandTrackingMode.BOTH).build() + session.configure(config) + Hand.right(session).state.sample(500.milliseconds).collect { rightHandState -> val bufferString = buildString { append("mapOf(") diff --git a/xr/src/main/java/com/example/xr/compose/Orbiter.kt b/xr/src/main/java/com/example/xr/compose/Orbiter.kt index e39ab491d..37dee2434 100644 --- a/xr/src/main/java/com/example/xr/compose/Orbiter.kt +++ b/xr/src/main/java/com/example/xr/compose/Orbiter.kt @@ -44,9 +44,8 @@ import androidx.xr.compose.subspace.SpatialRow import androidx.xr.compose.subspace.layout.SpatialRoundedCornerShape import androidx.xr.compose.subspace.layout.SubspaceModifier import androidx.xr.compose.subspace.layout.height +import androidx.xr.compose.subspace.layout.movable import androidx.xr.compose.subspace.layout.resizable -import androidx.xr.compose.subspace.layout.transformingMovable -import androidx.xr.compose.subspace.layout.transformingResizable import androidx.xr.compose.subspace.layout.width import androidx.xr.compose.unit.DpVolumeOffset import com.example.xr.R @@ -59,8 +58,8 @@ private fun OrbiterExampleSubspace() { SubspaceModifier .height(824.dp) .width(1400.dp) - .transformingResizable() - .transformingMovable(), + .resizable() + .movable(), ) { SpatialPanelContent() OrbiterExample() diff --git a/xr/src/main/java/com/example/xr/compose/SceneCoreEntity.kt b/xr/src/main/java/com/example/xr/compose/SceneCoreEntity.kt index ad2f66df2..6afdf0383 100644 --- a/xr/src/main/java/com/example/xr/compose/SceneCoreEntity.kt +++ b/xr/src/main/java/com/example/xr/compose/SceneCoreEntity.kt @@ -17,7 +17,6 @@ package com.example.xr.compose import androidx.compose.runtime.Composable -import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.xr.compose.platform.LocalSession import androidx.xr.compose.spatial.Subspace @@ -26,17 +25,17 @@ import androidx.xr.compose.subspace.SceneCoreEntitySizeAdapter import androidx.xr.compose.subspace.layout.SubspaceModifier import androidx.xr.compose.subspace.layout.offset import androidx.xr.compose.unit.IntVolumeSize -import androidx.xr.compose.unit.Meter import androidx.xr.runtime.math.FloatSize2d -import androidx.xr.runtime.math.IntSize2d import androidx.xr.runtime.math.Pose import androidx.xr.scenecore.SurfaceEntity +import androidx.xr.scenecore.scene @Composable fun SceneCoreEntityExample() { val session = LocalSession.current ?: return // [START androidxr_compose_SceneCoreEntity] - val density = LocalDensity.current + val virtualPixelDensity = session.scene.virtualPixelDensity + Subspace { SceneCoreEntity( modifier = SubspaceModifier.offset(x = 50.dp), @@ -58,8 +57,8 @@ fun SceneCoreEntityExample() { size: IntVolumeSize ) { val extents = FloatSize2d( - Meter.fromPixel(size.width.toFloat(), density).toM(), - Meter.fromPixel(size.height.toFloat(), density).toM(), + size.width.toFloat(), + size.height.toFloat() ) entity.shape = SurfaceEntity.Shape.Quad(extents) } diff --git a/xr/src/main/java/com/example/xr/compose/SpatialGltfModel.kt b/xr/src/main/java/com/example/xr/compose/SpatialGltfModel.kt index 7f2dc09ba..eac42ae6b 100644 --- a/xr/src/main/java/com/example/xr/compose/SpatialGltfModel.kt +++ b/xr/src/main/java/com/example/xr/compose/SpatialGltfModel.kt @@ -25,6 +25,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import androidx.xr.compose.platform.LocalSession +import androidx.xr.compose.subspace.ExperimentalSpatialGltfAnimationApi import androidx.xr.compose.subspace.SpatialGltfModel import androidx.xr.compose.subspace.SpatialGltfModelSource import androidx.xr.compose.subspace.layout.SubspaceModifier @@ -38,6 +39,7 @@ import androidx.xr.scenecore.Texture import java.nio.file.Paths import kotlin.io.path.Path +@OptIn(ExperimentalSpatialGltfAnimationApi::class) @Composable fun SpatialGltfModelExample(){ val xrSession = checkNotNull(LocalSession.current) @@ -132,7 +134,7 @@ fun SpatialGltfModelExample(){ // [END androidxr_compose_SpatialGltfModelTexture] // [START androidxr_compose_SpatialGltfModelAnimation] - val animation = modelState.animations.find { it.name == "Walk" } + val animation = modelState.getAnimations().find { it.name == "Walk" } animation?.animationState?.let { state -> LaunchedEffect(state) { diff --git a/xr/src/main/java/com/example/xr/compose/SpatialPanel.kt b/xr/src/main/java/com/example/xr/compose/SpatialPanel.kt index 5428714c3..209088af9 100644 --- a/xr/src/main/java/com/example/xr/compose/SpatialPanel.kt +++ b/xr/src/main/java/com/example/xr/compose/SpatialPanel.kt @@ -30,10 +30,12 @@ import androidx.compose.ui.unit.sp import androidx.xr.compose.platform.LocalSpatialCapabilities import androidx.xr.compose.spatial.Subspace import androidx.xr.compose.subspace.SpatialPanel +import androidx.xr.compose.subspace.layout.MovePolicy import androidx.xr.compose.subspace.layout.SubspaceModifier import androidx.xr.compose.subspace.layout.height +import androidx.xr.compose.subspace.layout.movable +import androidx.xr.compose.subspace.layout.resizable import androidx.xr.compose.subspace.layout.transformingMovable -import androidx.xr.compose.subspace.layout.transformingResizable import androidx.xr.compose.subspace.layout.width @Composable @@ -44,8 +46,8 @@ private fun SpatialPanelExample() { SubspaceModifier .height(824.dp) .width(1400.dp) - .transformingMovable() - .transformingResizable(), + .movable() + .resizable(), ) { SpatialPanelContent() } @@ -81,7 +83,7 @@ private fun ContentInSpatialPanel() { if (LocalSpatialCapabilities.current.isSpatialUiEnabled) { Subspace { SpatialPanel( - modifier = SubspaceModifier.transformingMovable().transformingResizable(), + modifier = SubspaceModifier.movable().resizable(), ) { AppContent() } diff --git a/xr/src/main/java/com/example/xr/glimmer/CardSamples.kt b/xr/src/main/java/com/example/xr/glimmer/CardSamples.kt index c673e3951..91ba830b4 100644 --- a/xr/src/main/java/com/example/xr/glimmer/CardSamples.kt +++ b/xr/src/main/java/com/example/xr/glimmer/CardSamples.kt @@ -22,6 +22,7 @@ import androidx.compose.material.icons.filled.Favorite import androidx.compose.runtime.Composable import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.res.painterResource +import androidx.xr.glimmer.ActionCard import androidx.xr.glimmer.Button import androidx.xr.glimmer.Card import androidx.xr.glimmer.GlimmerTheme @@ -34,7 +35,7 @@ private val FavoriteIcon = Icons.Default.Favorite @Composable fun CardSample() { val myHeaderImage = painterResource(id = android.R.drawable.ic_menu_gallery) - Card( + ActionCard( title = { Text("Card Title", style = GlimmerTheme.typography.titleMedium) }, subtitle = { Text("Sub-heading text", style = GlimmerTheme.typography.titleSmall) }, leadingIcon = { Icon(FavoriteIcon, contentDescription = "Favorite") }, diff --git a/xr/src/main/java/com/example/xr/projected/ProjectedMainActivity.kt b/xr/src/main/java/com/example/xr/projected/ProjectedMainActivity.kt index c6f541672..0bb54e273 100644 --- a/xr/src/main/java/com/example/xr/projected/ProjectedMainActivity.kt +++ b/xr/src/main/java/com/example/xr/projected/ProjectedMainActivity.kt @@ -35,8 +35,8 @@ import androidx.core.content.ContextCompat import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.lifecycleScope +import androidx.xr.glimmer.ActionCard import androidx.xr.glimmer.Button -import androidx.xr.glimmer.Card import androidx.xr.glimmer.GlimmerTheme import androidx.xr.glimmer.Text import androidx.xr.glimmer.surface @@ -57,6 +57,8 @@ class ProjectedMainActivity : ComponentActivity() { private var areVisualsOn by mutableStateOf(true) private var isPermissionDenied by mutableStateOf(false) + @Suppress("DEPRECATION") + // TODO: Remove suppression once Android Emulator supports ProjectedActivityCompat.requestPermissions() // [START androidxr_projected_permissions_launcher] // Register the permissions launcher using the ProjectedPermissionsResultContract. private val requestPermissionLauncher: ActivityResultLauncher> = @@ -158,7 +160,7 @@ fun HomeScreen( contentAlignment = Alignment.Center ) { if (isPermissionDenied) { - Card( + ActionCard( title = { Text("Permission Required") }, action = { Button(onClick = onClose) { Text("Exit") } } ) { @@ -166,7 +168,7 @@ fun HomeScreen( Button(onClick = onRetryPermission) { Text("Retry") } } } else if (isVisualUiSupported) { - Card( + ActionCard( title = { Text("Android XR") }, action = { Button(onClick = onClose) { diff --git a/xr/src/main/java/com/example/xr/runtime/DeviceLifecycle.kt b/xr/src/main/java/com/example/xr/runtime/DeviceLifecycle.kt index 5006dfc3b..e0040ae60 100644 --- a/xr/src/main/java/com/example/xr/runtime/DeviceLifecycle.kt +++ b/xr/src/main/java/com/example/xr/runtime/DeviceLifecycle.kt @@ -22,7 +22,6 @@ import androidx.annotation.RequiresApi import androidx.lifecycle.Lifecycle import androidx.xr.projected.ProjectedContext import androidx.xr.projected.experimental.ExperimentalProjectedApi -import androidx.xr.runtime.ExperimentalXrDeviceLifecycleApi import androidx.xr.runtime.XrDevice import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.currentCoroutineContext @@ -31,7 +30,6 @@ import kotlinx.coroutines.flow.flowOf @RequiresApi(Build.VERSION_CODES.BAKLAVA) @OptIn( - ExperimentalXrDeviceLifecycleApi::class, ExperimentalProjectedApi::class, ExperimentalCoroutinesApi::class, ) diff --git a/xr/src/main/java/com/example/xr/runtime/DisplayBlendMode.kt b/xr/src/main/java/com/example/xr/runtime/DisplayBlendMode.kt index ffe7bb865..b853db80a 100644 --- a/xr/src/main/java/com/example/xr/runtime/DisplayBlendMode.kt +++ b/xr/src/main/java/com/example/xr/runtime/DisplayBlendMode.kt @@ -20,10 +20,8 @@ import android.content.Context import androidx.xr.runtime.DisplayBlendMode.Companion.ADDITIVE import androidx.xr.runtime.DisplayBlendMode.Companion.ALPHA_BLEND import androidx.xr.runtime.DisplayBlendMode.Companion.NO_DISPLAY -import androidx.xr.runtime.ExperimentalXrDeviceLifecycleApi import androidx.xr.runtime.XrDevice -@OptIn(ExperimentalXrDeviceLifecycleApi::class) fun getPreferredBlendMode(context: Context) { // [START androidxr_runtime_getPreferredBlendMode] val preferredDisplayBlendMode = diff --git a/xr/src/main/java/com/example/xr/runtime/Session.kt b/xr/src/main/java/com/example/xr/runtime/Session.kt index 3001b4c08..c0e20e36f 100644 --- a/xr/src/main/java/com/example/xr/runtime/Session.kt +++ b/xr/src/main/java/com/example/xr/runtime/Session.kt @@ -19,9 +19,11 @@ package com.example.xr.runtime import android.content.Context import androidx.activity.ComponentActivity import androidx.compose.runtime.Composable +import androidx.lifecycle.lifecycleScope import androidx.xr.compose.platform.LocalSession import androidx.xr.runtime.Session import androidx.xr.runtime.SessionCreateSuccess +import kotlinx.coroutines.launch // [START androidxr_localsession] @Composable @@ -32,13 +34,15 @@ fun ComposableUsingSession() { fun ComponentActivity.createSession(context: Context) { // [START androidxr_session_create] - when (val result = Session.create(context)) { - is SessionCreateSuccess -> { - val xrSession = result.session - // ... + lifecycleScope.launch { + when (val result = Session.create(context)) { + is SessionCreateSuccess -> { + val xrSession = result.session + // ... + } + else -> + TODO(/* A different unhandled exception was thrown. */) } - else -> - TODO(/* A different unhandled exception was thrown. */) } // [END androidxr_session_create] } diff --git a/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt b/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt index ab9d48979..fc53c3983 100644 --- a/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt +++ b/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt @@ -21,6 +21,7 @@ import android.content.Intent import android.net.Uri import androidx.activity.ComponentActivity import androidx.xr.runtime.Session +import androidx.xr.scenecore.ExperimentalGltfAnimationApi import androidx.xr.scenecore.GltfAnimationStartOptions import androidx.xr.scenecore.GltfModel import androidx.xr.scenecore.GltfModelEntity @@ -42,9 +43,10 @@ private fun createModelEntity(session: Session, gltfModel: GltfModel) { // [END androidxr_scenecore_gltfmodelentity_create] } +@OptIn(ExperimentalGltfAnimationApi::class) private fun animateEntity(gltfEntity: GltfModelEntity) { // [START androidxr_scenecore_gltfmodelentity_animation] - val animation = gltfEntity.animations.find { it.name == "Walk" } + val animation = gltfEntity.getAnimations().find { it.name == "Walk" } animation?.start(GltfAnimationStartOptions(shouldLoop = true)) // [END androidxr_scenecore_gltfmodelentity_animation] } From bdaf19e5e6ff99f4405a8c73f80c8fbcb14ec871 Mon Sep 17 00:00:00 2001 From: Tram Bui Date: Thu, 9 Jul 2026 14:49:56 -0700 Subject: [PATCH 3/3] fix build issues and addres gemini feedback --- xr/src/main/java/com/example/xr/arcore/Hands.kt | 3 +-- .../test/java/com/example/xr/arcore/test/ArCoreTestRule.kt | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/xr/src/main/java/com/example/xr/arcore/Hands.kt b/xr/src/main/java/com/example/xr/arcore/Hands.kt index 97f8ba1cb..aa25563e2 100644 --- a/xr/src/main/java/com/example/xr/arcore/Hands.kt +++ b/xr/src/main/java/com/example/xr/arcore/Hands.kt @@ -17,7 +17,6 @@ package com.example.xr.arcore import android.app.Activity -import android.content.Context import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -154,7 +153,7 @@ class GenerateHandJointData : ComponentActivity() { super.onCreate(savedInstanceState) lifecycleScope.launch { - val session = (Session.create(context = this as Context) as SessionCreateSuccess).session + val session = (Session.create(context = this@GenerateHandJointData) as SessionCreateSuccess).session val config = Config.Builder(session.config).setHandTracking(HandTrackingMode.BOTH).build() session.configure(config) diff --git a/xr/src/test/java/com/example/xr/arcore/test/ArCoreTestRule.kt b/xr/src/test/java/com/example/xr/arcore/test/ArCoreTestRule.kt index e309624ad..b7242cec9 100644 --- a/xr/src/test/java/com/example/xr/arcore/test/ArCoreTestRule.kt +++ b/xr/src/test/java/com/example/xr/arcore/test/ArCoreTestRule.kt @@ -32,6 +32,7 @@ import androidx.xr.runtime.math.Vector3 import com.example.xr.arcore.detectThumbsUp import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.StandardTestDispatcher import kotlinx.coroutines.test.TestDispatcher import kotlinx.coroutines.test.TestScope @@ -69,8 +70,10 @@ class ArCoreTestRuleExample { activityController.create().start().resume() - val sessionCreateResult = Session.create(context = activity, coroutineContext = testDispatcher) - session = (sessionCreateResult as SessionCreateSuccess).session + runBlocking { + val sessionCreateResult = Session.create(context = activity, coroutineContext = testDispatcher) + session = (sessionCreateResult as SessionCreateSuccess).session + } // Configure the session. session.configure(Config.Builder(session.config).setHandTracking(HandTrackingMode.BOTH).build())