Skip to content

Commit 1f4d60b

Browse files
authored
Merge branch 'main' into bot-update-deps
2 parents dacdbcf + 015df95 commit 1f4d60b

File tree

22 files changed

+1687
-0
lines changed

22 files changed

+1687
-0
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.compose.snippets.components
18+
19+
import androidx.compose.foundation.layout.Box
20+
import androidx.compose.foundation.layout.fillMaxSize
21+
import androidx.compose.foundation.layout.padding
22+
import androidx.compose.material.icons.Icons
23+
import androidx.compose.material.icons.filled.Album
24+
import androidx.compose.material.icons.filled.MusicNote
25+
import androidx.compose.material.icons.filled.PlaylistAddCircle
26+
import androidx.compose.material3.ExperimentalMaterial3Api
27+
import androidx.compose.material3.Icon
28+
import androidx.compose.material3.NavigationBar
29+
import androidx.compose.material3.NavigationBarDefaults
30+
import androidx.compose.material3.NavigationBarItem
31+
import androidx.compose.material3.NavigationRail
32+
import androidx.compose.material3.NavigationRailItem
33+
import androidx.compose.material3.PrimaryTabRow
34+
import androidx.compose.material3.Scaffold
35+
import androidx.compose.material3.Tab
36+
import androidx.compose.material3.Text
37+
import androidx.compose.runtime.Composable
38+
import androidx.compose.runtime.getValue
39+
import androidx.compose.runtime.mutableIntStateOf
40+
import androidx.compose.runtime.saveable.rememberSaveable
41+
import androidx.compose.runtime.setValue
42+
import androidx.compose.ui.Alignment
43+
import androidx.compose.ui.Modifier
44+
import androidx.compose.ui.graphics.vector.ImageVector
45+
import androidx.compose.ui.text.style.TextOverflow
46+
import androidx.compose.ui.tooling.preview.Preview
47+
import androidx.navigation.NavHostController
48+
import androidx.navigation.compose.NavHost
49+
import androidx.navigation.compose.composable
50+
import androidx.navigation.compose.rememberNavController
51+
52+
@Composable
53+
fun SongsScreen(modifier: Modifier = Modifier) {
54+
Box(
55+
modifier = Modifier.fillMaxSize(),
56+
contentAlignment = Alignment.Center
57+
) {
58+
Text("Songs Screen")
59+
}
60+
}
61+
62+
@Composable
63+
fun AlbumScreen(modifier: Modifier = Modifier) {
64+
Box(
65+
modifier = Modifier.fillMaxSize(),
66+
contentAlignment = Alignment.Center
67+
) {
68+
Text("Album Screen")
69+
}
70+
}
71+
72+
@Composable
73+
fun PlaylistScreen(modifier: Modifier = Modifier) {
74+
Box(
75+
modifier = Modifier.fillMaxSize(),
76+
contentAlignment = Alignment.Center
77+
) {
78+
Text("Playlist Screen")
79+
}
80+
}
81+
82+
enum class Destination(
83+
val route: String,
84+
val label: String,
85+
val icon: ImageVector,
86+
val contentDescription: String
87+
) {
88+
SONGS("songs", "Songs", Icons.Default.MusicNote, "Songs"),
89+
ALBUM("album", "Album", Icons.Default.Album, "Album"),
90+
PLAYLISTS("playlist", "Playlist", Icons.Default.PlaylistAddCircle, "Playlist")
91+
}
92+
93+
@Composable
94+
fun AppNavHost(
95+
navController: NavHostController,
96+
startDestination: Destination,
97+
modifier: Modifier = Modifier
98+
) {
99+
NavHost(
100+
navController,
101+
startDestination = startDestination.route
102+
) {
103+
Destination.entries.forEach { destination ->
104+
composable(destination.route) {
105+
when (destination) {
106+
Destination.SONGS -> SongsScreen()
107+
Destination.ALBUM -> AlbumScreen()
108+
Destination.PLAYLISTS -> PlaylistScreen()
109+
}
110+
}
111+
}
112+
}
113+
}
114+
115+
@Preview()
116+
// [START android_compose_components_navigationbarexample]
117+
@Composable
118+
fun NavigationBarExample(modifier: Modifier = Modifier) {
119+
val navController = rememberNavController()
120+
val startDestination = Destination.SONGS
121+
var selectedDestination by rememberSaveable { mutableIntStateOf(startDestination.ordinal) }
122+
123+
Scaffold(
124+
modifier = modifier,
125+
bottomBar = {
126+
NavigationBar(windowInsets = NavigationBarDefaults.windowInsets) {
127+
Destination.entries.forEachIndexed { index, destination ->
128+
NavigationBarItem(
129+
selected = selectedDestination == index,
130+
onClick = {
131+
navController.navigate(route = destination.route)
132+
selectedDestination = index
133+
},
134+
icon = {
135+
Icon(
136+
destination.icon,
137+
contentDescription = destination.contentDescription
138+
)
139+
},
140+
label = { Text(destination.label) }
141+
)
142+
}
143+
}
144+
}
145+
) { contentPadding ->
146+
AppNavHost(navController, startDestination, modifier = Modifier.padding(contentPadding))
147+
}
148+
}
149+
// [END android_compose_components_navigationbarexample]
150+
151+
@Preview()
152+
// [START android_compose_components_navigationrailexample]
153+
@Composable
154+
fun NavigationRailExample(modifier: Modifier = Modifier) {
155+
val navController = rememberNavController()
156+
val startDestination = Destination.SONGS
157+
var selectedDestination by rememberSaveable { mutableIntStateOf(startDestination.ordinal) }
158+
159+
Scaffold(modifier = modifier) { contentPadding ->
160+
NavigationRail(modifier = Modifier.padding(contentPadding)) {
161+
Destination.entries.forEachIndexed { index, destination ->
162+
NavigationRailItem(
163+
selected = selectedDestination == index,
164+
onClick = {
165+
navController.navigate(route = destination.route)
166+
selectedDestination = index
167+
},
168+
icon = {
169+
Icon(
170+
destination.icon,
171+
contentDescription = destination.contentDescription
172+
)
173+
},
174+
label = { Text(destination.label) }
175+
)
176+
}
177+
}
178+
AppNavHost(navController, startDestination)
179+
}
180+
}
181+
// [END android_compose_components_navigationrailexample]
182+
183+
@OptIn(ExperimentalMaterial3Api::class)
184+
@Preview(showBackground = true)
185+
// [START android_compose_components_navigationtabexample]
186+
@Composable
187+
fun NavigationTabExample(modifier: Modifier = Modifier) {
188+
val navController = rememberNavController()
189+
val startDestination = Destination.SONGS
190+
var selectedDestination by rememberSaveable { mutableIntStateOf(startDestination.ordinal) }
191+
192+
Scaffold(modifier = modifier) { contentPadding ->
193+
PrimaryTabRow(selectedTabIndex = selectedDestination, modifier = Modifier.padding(contentPadding)) {
194+
Destination.entries.forEachIndexed { index, destination ->
195+
Tab(
196+
selected = selectedDestination == index,
197+
onClick = {
198+
navController.navigate(route = destination.route)
199+
selectedDestination = index
200+
},
201+
text = {
202+
Text(
203+
text = destination.label,
204+
maxLines = 2,
205+
overflow = TextOverflow.Ellipsis
206+
)
207+
}
208+
)
209+
}
210+
}
211+
AppNavHost(navController, startDestination)
212+
}
213+
}
214+
// [END android_compose_components_navigationtabexample]

xr/build.gradle.kts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
plugins {
22
alias(libs.plugins.android.application)
33
alias(libs.plugins.kotlin.android)
4+
alias(libs.plugins.compose.compiler)
45
}
56

67
android {
@@ -21,14 +22,47 @@ android {
2122
kotlinOptions {
2223
jvmTarget = "11"
2324
}
25+
buildFeatures {
26+
compose = true
27+
}
2428
}
2529

2630
dependencies {
2731
implementation(libs.androidx.xr.arcore)
2832
implementation(libs.androidx.xr.scenecore)
2933
implementation(libs.androidx.xr.compose)
34+
3035
implementation(libs.androidx.activity.ktx)
3136
implementation(libs.guava)
3237
implementation(libs.kotlinx.coroutines.guava)
3338

39+
implementation(libs.androidx.media3.exoplayer)
40+
41+
val composeBom = platform(libs.androidx.compose.bom)
42+
implementation(composeBom)
43+
44+
implementation(libs.androidx.compose.ui)
45+
implementation(libs.androidx.compose.ui.util)
46+
implementation(libs.androidx.compose.ui.graphics)
47+
implementation(libs.androidx.graphics.shapes)
48+
implementation(libs.androidx.compose.ui.tooling.preview)
49+
implementation(libs.androidx.compose.ui.viewbinding)
50+
implementation(libs.androidx.paging.compose)
51+
implementation(libs.androidx.compose.animation.graphics)
52+
53+
implementation(libs.androidx.compose.material3)
54+
implementation(libs.androidx.compose.material3.adaptive)
55+
implementation(libs.androidx.compose.material3.adaptive.layout)
56+
implementation(libs.androidx.compose.material3.adaptive.navigation)
57+
implementation(libs.androidx.compose.material3.adaptive.navigation.suite)
58+
implementation(libs.androidx.compose.material)
59+
60+
implementation(libs.androidx.compose.runtime)
61+
implementation(libs.androidx.compose.runtime.livedata)
62+
implementation(libs.androidx.compose.material.iconsExtended)
63+
implementation(libs.androidx.compose.material.ripple)
64+
implementation(libs.androidx.constraintlayout.compose)
65+
66+
implementation(libs.androidx.activity.compose)
67+
implementation(libs.androidx.appcompat)
3468
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.xr.arcore
18+
19+
import androidx.xr.arcore.Anchor
20+
import androidx.xr.arcore.AnchorCreateSuccess
21+
import androidx.xr.runtime.Session
22+
import java.util.UUID
23+
24+
private suspend fun persistAnchor(anchor: Anchor) {
25+
// [START androidxr_arcore_anchor_persist]
26+
val uuid = anchor.persist()
27+
// [END androidxr_arcore_anchor_persist]
28+
}
29+
30+
private fun loadAnchor(session: Session, uuid: UUID) {
31+
// [START androidxr_arcore_anchor_load]
32+
when (val result = Anchor.load(session, uuid)) {
33+
is AnchorCreateSuccess -> {
34+
// Loading was successful. The anchor is stored in result.anchor.
35+
}
36+
else -> {
37+
// handle failure
38+
}
39+
}
40+
// [END androidxr_arcore_anchor_load]
41+
}
42+
43+
private fun unpersistAnchor(session: Session, uuid: UUID) {
44+
// [START androidxr_arcore_anchor_unpersist]
45+
Anchor.unpersist(session, uuid)
46+
// [END androidxr_arcore_anchor_unpersist]
47+
}
48+
49+
private fun getPersistedAnchorUuids(session: Session) {
50+
// [START androidxr_arcore_anchor_get_uuids]
51+
val uuids = Anchor.getPersistedAnchorUuids(session)
52+
// [END androidxr_arcore_anchor_get_uuids]
53+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2025 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.xr.arcore
18+
19+
import androidx.xr.arcore.Anchor
20+
import androidx.xr.arcore.AnchorCreateSuccess
21+
import androidx.xr.arcore.Trackable
22+
import androidx.xr.runtime.Session
23+
import androidx.xr.runtime.math.Pose
24+
import androidx.xr.scenecore.AnchorEntity
25+
import androidx.xr.scenecore.Entity
26+
27+
private fun createAnchorAtPose(session: Session, pose: Pose) {
28+
val pose = Pose()
29+
// [START androidxr_arcore_anchor_create]
30+
when (val result = Anchor.create(session, pose)) {
31+
is AnchorCreateSuccess -> { /* anchor stored in `result.anchor`. */ }
32+
else -> { /* handle failure */ }
33+
}
34+
// [END androidxr_arcore_anchor_create]
35+
}
36+
37+
private fun createAnchorAtTrackable(trackable: Trackable<*>) {
38+
val pose = Pose()
39+
// [START androidxr_arcore_anchor_create_trackable]
40+
when (val result = trackable.createAnchor(pose)) {
41+
is AnchorCreateSuccess -> { /* anchor stored in `result.anchor`. */ }
42+
else -> { /* handle failure */ }
43+
}
44+
// [END androidxr_arcore_anchor_create_trackable]
45+
}
46+
47+
private fun attachEntityToAnchor(
48+
session: androidx.xr.scenecore.Session,
49+
entity: Entity,
50+
anchor: Anchor
51+
) {
52+
// [START androidxr_arcore_entity_tracks_anchor]
53+
AnchorEntity.create(session, anchor).apply {
54+
setParent(session.activitySpace)
55+
addChild(entity)
56+
}
57+
// [END androidxr_arcore_entity_tracks_anchor]
58+
}

0 commit comments

Comments
 (0)