Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ android.enableR8.fullMode=true

# Use an AndroidX snapshot build.
# https://androidx.dev/snapshots/builds
# snapshotVersion=14793336
snapshotVersion=15770982

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forget, if we set a snapshot version, does this have impact on other teams?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If other teams were relying on an older snapshot release and the API changing between the publication of a snippet but that's extremely rare. Once the release is ready, we don't really change it, we upgrade the version number. I would say if we uncomment this line, it should be commented back within 2 weeks (Jetpack release cycle)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The intention is that the PR author reverts the change to this file - this change is to help XR team members synchronize on the same snapshot version. When Jetpack goes live, we revert the change to snapshotVersion and merge into main.

4 changes: 2 additions & 2 deletions xr/src/main/java/com/example/xr/arcore/Anchors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm that we are handling this name change properly - is this a breaking change or is AnchorEntity still available and marked as depracated?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a breaking change. Any code using the old AnchorEntity class will need to be updated to use AnchorSpace.

import androidx.xr.scenecore.AnchorSpace
import androidx.xr.scenecore.Entity
import androidx.xr.scenecore.scene

Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 0 additions & 2 deletions xr/src/main/java/com/example/xr/arcore/DepthMaps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions xr/src/main/java/com/example/xr/arcore/Hands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,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@GenerateHandJointData) as SessionCreateSuccess).session

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my own understanding, what does the syntax of @GenerateHandJointData do here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this refers to lifecycleScope given that it's within its block. By putting @GenerateHandJointData, you go one level higher, which is an Activity and it's castable as a `Context

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(")
Expand Down
7 changes: 3 additions & 4 deletions xr/src/main/java/com/example/xr/compose/Orbiter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -59,8 +58,8 @@ private fun OrbiterExampleSubspace() {
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.transformingResizable()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question here - how is this deprecation being handled?

Do we have enough changes that we should think about doing a migration guide? Or perhaps a few things we should highlight in the Beta Blog post in August?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @amyZepp would be a good person to make that call. What do you think Amy?

.transformingMovable(),
.resizable()
.movable(),
) {
SpatialPanelContent()
OrbiterExample()
Expand Down
11 changes: 5 additions & 6 deletions xr/src/main/java/com/example/xr/compose/SceneCoreEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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),
Expand All @@ -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()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the data we are returning from these values fundamentally different now?

I am trying to understand if we have a sneaky breaking change that might be hard to detect and leading to bugs.

)
Comment on lines 59 to 62

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The size parameter in onLayoutSizeChanged represents the layout dimensions in pixels (or virtual pixels). Directly passing size.width.toFloat() and size.height.toFloat() to FloatSize2d without converting them to meters will result in an extremely large quad (e.g., hundreds or thousands of meters wide/high). You should use the virtualPixelDensity retrieved on line 37 to perform the conversion from pixels to meters.

Suggested change
val extents = FloatSize2d(
Meter.fromPixel(size.width.toFloat(), density).toM(),
Meter.fromPixel(size.height.toFloat(), density).toM(),
size.width.toFloat(),
size.height.toFloat()
)
val extents = FloatSize2d(
virtualPixelDensity.pxToMeters(size.width.toFloat()),
virtualPixelDensity.pxToMeters(size.height.toFloat())
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The suggest didn't work due to the unresolved reference pxToMeters

entity.shape = SurfaceEntity.Shape.Quad(extents)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 6 additions & 4 deletions xr/src/main/java/com/example/xr/compose/SpatialPanel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,8 +46,8 @@ private fun SpatialPanelExample() {
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.transformingMovable()
.transformingResizable(),
.movable()
.resizable(),
) {
SpatialPanelContent()
}
Expand Down Expand Up @@ -81,7 +83,7 @@ private fun ContentInSpatialPanel() {
if (LocalSpatialCapabilities.current.isSpatialUiEnabled) {
Subspace {
SpatialPanel(
modifier = SubspaceModifier.transformingMovable().transformingResizable(),
modifier = SubspaceModifier.movable().resizable(),
) {
AppContent()
}
Expand Down
3 changes: 2 additions & 1 deletion xr/src/main/java/com/example/xr/glimmer/CardSamples.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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") },
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<List<ProjectedPermissionsRequestParams>> =
Expand Down Expand Up @@ -158,15 +160,15 @@ fun HomeScreen(
contentAlignment = Alignment.Center
) {
if (isPermissionDenied) {
Card(
ActionCard(
title = { Text("Permission Required") },
action = { Button(onClick = onClose) { Text("Exit") } }
) {
Text("Camera access is needed to use AI glasses features.")
Button(onClick = onRetryPermission) { Text("Retry") }
}
} else if (isVisualUiSupported) {
Card(
ActionCard(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting API change. Same concerns re depracation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the glimmer Card composable has an action parameter, it is a breaking change (which it is in this case). The glimmer Card composable still exists.

title = { Text("Android XR") },
action = {
Button(onClick = onClose) {
Expand Down
2 changes: 0 additions & 2 deletions xr/src/main/java/com/example/xr/runtime/DeviceLifecycle.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -31,7 +30,6 @@ import kotlinx.coroutines.flow.flowOf

@RequiresApi(Build.VERSION_CODES.BAKLAVA)
@OptIn(
ExperimentalXrDeviceLifecycleApi::class,
ExperimentalProjectedApi::class,
ExperimentalCoroutinesApi::class,
)
Expand Down
2 changes: 0 additions & 2 deletions xr/src/main/java/com/example/xr/runtime/DisplayBlendMode.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
16 changes: 10 additions & 6 deletions xr/src/main/java/com/example/xr/runtime/Session.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
}
4 changes: 3 additions & 1 deletion xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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())
Expand Down
Loading