Skip to content
Merged
9 changes: 3 additions & 6 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,9 @@ androidx-test-junit = "1.2.1"
androidx-window = "1.5.0-alpha02"
androidx-window-core = "1.5.0-alpha02"
androidx-window-java = "1.5.0-alpha02"
# @keep
androidx-xr = "1.0.0-alpha03"
# @keep
androidx-xr-arcore = "1.0.0-alpha04"
androidx-xr-compose = "1.0.0-alpha04"
androidx-xr-scenecore = "1.0.0-alpha04"
androidx-xr-arcore = "1.0.0-alpha05"
androidx-xr-scenecore = "1.0.0-alpha05"
androidx-xr-compose = "1.0.0-alpha05"
androidxHiltNavigationCompose = "1.2.0"
appcompat = "1.7.1"
coil = "2.7.0"
Expand Down
5 changes: 3 additions & 2 deletions xr/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ android {
buildFeatures {
compose = true
}
lint {
disable += "RestrictedApi"
}
}

dependencies {
Expand All @@ -33,8 +36,6 @@ dependencies {
implementation(libs.androidx.xr.compose)

implementation(libs.androidx.activity.ktx)
implementation(libs.guava)
implementation(libs.kotlinx.coroutines.guava)

implementation(libs.androidx.media3.exoplayer)

Expand Down
10 changes: 4 additions & 6 deletions xr/src/main/java/com/example/xr/arcore/Anchors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,25 +22,23 @@ import androidx.xr.arcore.Trackable
import androidx.xr.runtime.Config
import androidx.xr.runtime.Session
import androidx.xr.runtime.SessionConfigureConfigurationNotSupported
import androidx.xr.runtime.SessionConfigurePermissionsNotGranted
import androidx.xr.runtime.SessionConfigureSuccess
import androidx.xr.runtime.math.Pose
import androidx.xr.scenecore.AnchorEntity
import androidx.xr.scenecore.Entity
import androidx.xr.scenecore.scene

@Suppress("RestrictedApi") // b/416288516 - session.config and session.configure() are incorrectly restricted
fun configureAnchoring(session: Session) {
// [START androidxr_arcore_anchoring_configure]
val newConfig = session.config.copy(
anchorPersistence = Config.AnchorPersistenceMode.Enabled,
anchorPersistence = Config.AnchorPersistenceMode.LOCAL,
)
when (val result = session.configure(newConfig)) {
is SessionConfigureConfigurationNotSupported ->
TODO(/* Some combinations of configurations are not valid. Handle this failure case. */)
is SessionConfigurePermissionsNotGranted ->
TODO(/* The required permissions in result.permissions have not been granted. */)
is SessionConfigureSuccess -> TODO(/* Success! */)
else ->
TODO(/* A different unhandled exception was thrown. */)
}
// [END androidxr_arcore_anchoring_configure]
}
Expand Down Expand Up @@ -72,7 +70,7 @@ private fun attachEntityToAnchor(
) {
// [START androidxr_arcore_entity_tracks_anchor]
AnchorEntity.create(session, anchor).apply {
setParent(session.scene.activitySpace)
parent = session.scene.activitySpace
addChild(entity)
}
// [END androidxr_arcore_entity_tracks_anchor]
Expand Down
16 changes: 7 additions & 9 deletions xr/src/main/java/com/example/xr/arcore/Hands.kt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import androidx.xr.runtime.Config
import androidx.xr.runtime.HandJointType
import androidx.xr.runtime.Session
import androidx.xr.runtime.SessionConfigureConfigurationNotSupported
import androidx.xr.runtime.SessionConfigurePermissionsNotGranted
import androidx.xr.runtime.SessionConfigureSuccess
import androidx.xr.runtime.math.Pose
import androidx.xr.runtime.math.Quaternion
Expand All @@ -35,18 +34,17 @@ import androidx.xr.scenecore.scene
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.launch

@Suppress("RestrictedApi") // b/416288516 - session.config and session.configure() are incorrectly restricted
fun ComponentActivity.configureSession(session: Session) {
// [START androidxr_arcore_hand_configure]
val newConfig = session.config.copy(
handTracking = Config.HandTrackingMode.Enabled
handTracking = Config.HandTrackingMode.BOTH
)
when (val result = session.configure(newConfig)) {
is SessionConfigureConfigurationNotSupported ->
TODO(/* Some combinations of configurations are not valid. Handle this failure case. */)
is SessionConfigurePermissionsNotGranted ->
TODO(/* The required permissions in result.permissions have not been granted. */)
is SessionConfigureSuccess -> TODO(/* Success! */)
else ->
TODO(/* A different unhandled exception was thrown. */)
}
// [END androidxr_arcore_hand_configure]
}
Expand All @@ -71,8 +69,8 @@ fun ComponentActivity.collectHands(session: Session) {
fun secondaryHandDetection(activity: Activity, session: Session) {
fun detectGesture(handState: Flow<Hand.State>) {}
// [START androidxr_arcore_hand_handedness]
val handedness = Hand.getHandedness(activity.contentResolver)
val secondaryHand = if (handedness == Hand.Handedness.LEFT) Hand.right(session) else Hand.left(session)
val handedness = Hand.getPrimaryHandSide(activity.contentResolver)
val secondaryHand = if (handedness == Hand.HandSide.LEFT) Hand.right(session) else Hand.left(session)
val handState = secondaryHand?.state ?: return
detectGesture(handState)
// [END androidxr_arcore_hand_handedness]
Expand All @@ -86,7 +84,7 @@ fun ComponentActivity.renderPlanetAtHandPalm(leftHandState: Hand.State) {

// the down direction points in the same direction as the palm
val angle = Vector3.angleBetween(palmPose.rotation * Vector3.Down, Vector3.Up)
palmEntity.setHidden(angle > Math.toRadians(40.0))
palmEntity.setEnabled(angle > Math.toRadians(40.0))

val transformedPose =
session.scene.perceptionSpace.transformPoseTo(
Expand All @@ -107,7 +105,7 @@ fun ComponentActivity.renderPlanetAtFingerTip(rightHandState: Hand.State) {

// the forward direction points towards the finger tip.
val angle = Vector3.angleBetween(tipPose.rotation * Vector3.Forward, Vector3.Up)
indexFingerEntity.setHidden(angle > Math.toRadians(40.0))
indexFingerEntity.setEnabled(angle > Math.toRadians(40.0))

val transformedPose =
session.scene.perceptionSpace.transformPoseTo(
Expand Down
10 changes: 4 additions & 6 deletions xr/src/main/java/com/example/xr/arcore/Planes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,22 @@ import androidx.xr.arcore.Plane
import androidx.xr.runtime.Config
import androidx.xr.runtime.Session
import androidx.xr.runtime.SessionConfigureConfigurationNotSupported
import androidx.xr.runtime.SessionConfigurePermissionsNotGranted
import androidx.xr.runtime.SessionConfigureSuccess
import androidx.xr.runtime.math.Pose
import androidx.xr.runtime.math.Ray
import androidx.xr.scenecore.scene

@Suppress("RestrictedApi") // b/416288516 - session.config and session.configure() are incorrectly restricted
fun configurePlaneTracking(session: Session) {
// [START androidxr_arcore_planetracking_configure]
val newConfig = session.config.copy(
planeTracking = Config.PlaneTrackingMode.HorizontalAndVertical,
planeTracking = Config.PlaneTrackingMode.HORIZONTAL_AND_VERTICAL,
)
when (val result = session.configure(newConfig)) {
is SessionConfigureConfigurationNotSupported ->
TODO(/* Some combinations of configurations are not valid. Handle this failure case. */)
is SessionConfigurePermissionsNotGranted ->
TODO(/* The required permissions in result.permissions have not been granted. */)
is SessionConfigureSuccess -> TODO(/* Success! */)
else ->
TODO(/* A different unhandled exception was thrown. */)
}
// [END androidxr_arcore_planetracking_configure]
}
Expand All @@ -58,7 +56,7 @@ private fun hitTestTable(session: Session) {
// When interested in the first Table hit:
val tableHit = results.firstOrNull {
val trackable = it.trackable
trackable is Plane && trackable.state.value.label == Plane.Label.Table
trackable is Plane && trackable.state.value.label == Plane.Label.TABLE
}
// [END androidxr_arcore_hitTest]
}
19 changes: 10 additions & 9 deletions xr/src/main/java/com/example/xr/compose/Orbiter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.CornerSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
Expand All @@ -36,9 +36,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.xr.compose.spatial.EdgeOffset
import androidx.xr.compose.spatial.ContentEdge
import androidx.xr.compose.spatial.Orbiter
import androidx.xr.compose.spatial.OrbiterEdge
import androidx.xr.compose.spatial.OrbiterOffsetType
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.SpatialRow
Expand Down Expand Up @@ -72,7 +72,7 @@ private fun OrbiterExampleSubspace() {
@Composable
fun OrbiterExample() {
Orbiter(
position = OrbiterEdge.Bottom,
position = ContentEdge.Bottom,
offset = 96.dp,
alignment = Alignment.CenterHorizontally
) {
Expand Down Expand Up @@ -102,13 +102,14 @@ fun OrbiterAnchoringExample() {
Subspace {
SpatialRow {
Orbiter(
position = OrbiterEdge.Top,
offset = EdgeOffset.inner(8.dp),
position = ContentEdge.Top,
offset = 8.dp,
offsetType = OrbiterOffsetType.InnerEdge,
shape = SpatialRoundedCornerShape(size = CornerSize(50))
) {
Text(
"Hello World!",
style = MaterialTheme.typography.h2,
style = MaterialTheme.typography.titleMedium,
modifier = Modifier
.background(Color.White)
.padding(16.dp)
Expand Down Expand Up @@ -150,7 +151,7 @@ private fun Ui2DToOribiter() {

// New XR differentiated approach
Orbiter(
position = OrbiterEdge.Start,
position = ContentEdge.Start,
offset = dimensionResource(R.dimen.start_orbiter_padding),
alignment = Alignment.Top
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ private fun ComposableThatShouldElevateInXr() {}
private fun SpatialElevationExample() {
// [START androidxr_compose_spatialelevation]
// Elevate an otherwise 2D Composable (signified here by ComposableThatShouldElevateInXr).
SpatialElevation(spatialElevationLevel = SpatialElevationLevel.Level4) {
SpatialElevation(elevation = SpatialElevationLevel.Level4) {
ComposableThatShouldElevateInXr()
}
// [END androidxr_compose_spatialelevation]
Expand Down
47 changes: 47 additions & 0 deletions xr/src/main/java/com/example/xr/compose/SpatialExternalSurface.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,23 @@ package com.example.xr.compose
import android.content.ContentResolver
import android.net.Uri
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ExperimentalComposeApi
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.media3.common.C
import androidx.media3.common.MediaItem
import androidx.media3.exoplayer.ExoPlayer
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.SpatialExternalSurface
import androidx.xr.compose.subspace.StereoMode
import androidx.xr.compose.subspace.SurfaceProtection
import androidx.xr.compose.subspace.layout.SubspaceModifier
import androidx.xr.compose.subspace.layout.height
import androidx.xr.compose.subspace.layout.width

// [START androidxr_compose_SpatialExternalSurfaceStereo]
@OptIn(ExperimentalComposeApi::class)
@Composable
fun SpatialExternalSurfaceContent() {
val context = LocalContext.current
Expand Down Expand Up @@ -69,3 +73,46 @@ fun SpatialExternalSurfaceContent() {
}
}
// [END androidxr_compose_SpatialExternalSurfaceStereo]

// [START androidxr_compose_SpatialExternalSurfaceDRM]
@OptIn(ExperimentalComposeApi::class)
@Composable
fun DrmSpatialVideoPlayer() {
val context = LocalContext.current
Subspace {
SpatialExternalSurface(
modifier = SubspaceModifier
.width(1200.dp)
.height(676.dp),
stereoMode = StereoMode.SideBySide,
surfaceProtection = SurfaceProtection.Protected
) {
val exoPlayer = remember { ExoPlayer.Builder(context).build() }

// Define the URI for your DRM-protected content and license server.
val videoUri = "https://your-content-provider.com/video.mpd"
val drmLicenseUrl = "https://your-license-server.com/license"

// Build a MediaItem with the necessary DRM configuration.
val mediaItem = MediaItem.Builder()
.setUri(videoUri)
.setDrmConfiguration(
MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
.setLicenseUri(drmLicenseUrl)
.build()
)
.build()

onSurfaceCreated { surface ->
// The created surface is secure and can be used by the player.
exoPlayer.setVideoSurface(surface)
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.play()
}

onSurfaceDestroyed { exoPlayer.release() }
}
}
}
// [END androidxr_compose_SpatialExternalSurfaceDRM]
4 changes: 2 additions & 2 deletions xr/src/main/java/com/example/xr/compose/Views.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ import androidx.xr.compose.subspace.layout.depth
import androidx.xr.compose.subspace.layout.height
import androidx.xr.compose.subspace.layout.width
import androidx.xr.runtime.Session
import androidx.xr.runtime.math.IntSize2d
import androidx.xr.scenecore.PanelEntity
import androidx.xr.scenecore.PixelDimensions
import com.example.xr.R

private class MyCustomView(context: Context) : View(context)
Expand Down Expand Up @@ -86,7 +86,7 @@ fun ComponentActivity.PanelEntityWithView(xrSession: Session) {
val panelEntity = PanelEntity.create(
session = xrSession,
view = panelContent,
pixelDimensions = PixelDimensions(500, 500),
pixelDimensions = IntSize2d(500, 500),
name = "panel entity"
)
// [END androidxr_compose_PanelEntityWithView]
Expand Down
2 changes: 2 additions & 0 deletions xr/src/main/java/com/example/xr/compose/Volume.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.xr.compose.platform.LocalSession
import androidx.xr.compose.spatial.Subspace
import androidx.xr.compose.subspace.ExperimentalSubspaceVolumeApi
import androidx.xr.compose.subspace.SpatialPanel
import androidx.xr.compose.subspace.Volume
import androidx.xr.compose.subspace.layout.SubspaceModifier
Expand Down Expand Up @@ -62,6 +63,7 @@ private fun VolumeExample() {
}

// [START androidxr_compose_ObjectInAVolume]
@OptIn(ExperimentalSubspaceVolumeApi::class)
@Composable
fun ObjectInAVolume(show3DObject: Boolean) {
// [START_EXCLUDE silent]
Expand Down
2 changes: 1 addition & 1 deletion xr/src/main/java/com/example/xr/misc/ModeTransition.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ fun modeTransitionCompose() {

fun modeTransitionScenecore(xrSession: Session) {
// [START androidxr_misc_modeTransitionScenecore]
xrSession.scene.spatialEnvironment.requestHomeSpaceMode()
xrSession.scene.requestHomeSpaceMode()
// [END androidxr_misc_modeTransitionScenecore]
}
Loading