diff --git a/xr/src/main/java/com/example/xr/compose/SpatialCapabilities.kt b/xr/src/main/java/com/example/xr/compose/SpatialCapabilities.kt index 13196e221..b3af88c13 100644 --- a/xr/src/main/java/com/example/xr/compose/SpatialCapabilities.kt +++ b/xr/src/main/java/com/example/xr/compose/SpatialCapabilities.kt @@ -17,7 +17,13 @@ package com.example.xr.compose import androidx.compose.runtime.Composable +import androidx.compose.ui.unit.dp import androidx.xr.compose.platform.LocalSpatialCapabilities +import androidx.xr.compose.spatial.Subspace +import androidx.xr.compose.subspace.SpatialPanel +import androidx.xr.compose.subspace.layout.SubspaceModifier +import androidx.xr.compose.subspace.layout.fillMaxHeight +import androidx.xr.compose.subspace.layout.width @Composable private fun SupportingInfoPanel() {} @@ -38,3 +44,25 @@ private fun SpatialCapabilitiesCheck() { val spatialAudioEnabled = LocalSpatialCapabilities.current.isSpatialAudioEnabled // [END androidxr_compose_checkSpatialCapabilities] } + +@Composable +private fun checkSpatialUiEnabled() { + // [START androidxr_compose_checkSpatialUiEnabled] + if (LocalSpatialCapabilities.current.isSpatialUiEnabled) { + Subspace { + SpatialPanel( + modifier = SubspaceModifier + .width(1488.dp) + .fillMaxHeight() + ) { + AppContent() + } + } + } else { + AppContent() + } + // [END androidxr_compose_checkSpatialUiEnabled] +} + +@Composable +private fun AppContent() {} diff --git a/xr/src/main/java/com/example/xr/misc/ModeTransition.kt b/xr/src/main/java/com/example/xr/misc/ModeTransition.kt new file mode 100644 index 000000000..c34d549ae --- /dev/null +++ b/xr/src/main/java/com/example/xr/misc/ModeTransition.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.xr.misc + +import androidx.compose.runtime.Composable +import androidx.xr.compose.platform.LocalSpatialConfiguration +import androidx.xr.scenecore.Session + +@Composable +fun modeTransitionCompose() { + // [START androidxr_misc_modeTransitionCompose] + LocalSpatialConfiguration.current.requestHomeSpaceMode() + // or + LocalSpatialConfiguration.current.requestFullSpaceMode() + // [END androidxr_misc_modeTransitionCompose] +} + +fun modeTransitionScenecore(xrSession: Session) { + // [START androidxr_misc_modeTransitionScenecore] + xrSession.spatialEnvironment.requestHomeSpaceMode() + // [END androidxr_misc_modeTransitionScenecore] +} diff --git a/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt b/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt new file mode 100644 index 000000000..6be959836 --- /dev/null +++ b/xr/src/main/java/com/example/xr/scenecore/GltfEntity.kt @@ -0,0 +1,64 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.xr.scenecore + +import android.content.Intent +import android.net.Uri +import androidx.activity.ComponentActivity +import androidx.xr.scenecore.GltfModel +import androidx.xr.scenecore.GltfModelEntity +import androidx.xr.scenecore.Session +import androidx.xr.scenecore.SpatialCapabilities +import androidx.xr.scenecore.getSpatialCapabilities +import kotlinx.coroutines.guava.await + +private suspend fun loadGltfFile(session: Session) { + // [START androidxr_scenecore_gltfmodel_create] + val gltfModel = GltfModel.create(session, "models/saturn_rings.glb").await() + // [END androidxr_scenecore_gltfmodel_create] +} + +private fun createModelEntity(session: Session, gltfModel: GltfModel) { + // [START androidxr_scenecore_gltfmodelentity_create] + if (session.getSpatialCapabilities() + .hasCapability(SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT) + ) { + val gltfEntity = GltfModelEntity.create(session, gltfModel) + } + // [END androidxr_scenecore_gltfmodelentity_create] +} + +private fun animateEntity(gltfEntity: GltfModelEntity) { + // [START androidxr_scenecore_gltfmodelentity_animation] + gltfEntity.startAnimation(loop = true, animationName = "Walk") + // [END androidxr_scenecore_gltfmodelentity_animation] +} + +private fun ComponentActivity.startSceneViewer() { + // [START androidxr_scenecore_sceneviewer] + val url = + "https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/FlightHelmet/glTF/FlightHelmet.gltf" + val sceneViewerIntent = Intent(Intent.ACTION_VIEW) + val intentUri = + Uri.parse("https://arvr.google.com/scene-viewer/1.2") + .buildUpon() + .appendQueryParameter("file", url) + .build() + sceneViewerIntent.setDataAndType(intentUri, "model/gltf-binary") + startActivity(sceneViewerIntent) + // [END androidxr_scenecore_sceneviewer] +} diff --git a/xr/src/main/java/com/example/xr/scenecore/SpatialCapabilities.kt b/xr/src/main/java/com/example/xr/scenecore/SpatialCapabilities.kt new file mode 100644 index 000000000..9d041eeac --- /dev/null +++ b/xr/src/main/java/com/example/xr/scenecore/SpatialCapabilities.kt @@ -0,0 +1,41 @@ +/* + * Copyright 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.xr.scenecore + +import androidx.xr.scenecore.Session +import androidx.xr.scenecore.SpatialCapabilities +import androidx.xr.scenecore.getSpatialCapabilities + +fun checkMultipleCapabilities(xrSession: Session) { + // [START androidxr_compose_checkMultipleCapabilities] + // Example 1: check if enabling passthrough mode is allowed + if (xrSession.getSpatialCapabilities().hasCapability( + SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL + ) + ) { + xrSession.spatialEnvironment.setPassthroughOpacityPreference(0f) + } + // Example 2: multiple capability flags can be checked simultaneously: + if (xrSession.getSpatialCapabilities().hasCapability( + SpatialCapabilities.SPATIAL_CAPABILITY_PASSTHROUGH_CONTROL and + SpatialCapabilities.SPATIAL_CAPABILITY_3D_CONTENT + ) + ) { + // ... + } + // [END androidxr_compose_checkMultipleCapabilities] +}