Mit Android XR kannst du deine Apps nicht nur auf dem Bildschirm, sondern auch in der realen Welt verankern. In dieser Session erfahren Sie, wie Sie mit Jetpack Compose Glimmer und der Geospatial API von ARCore ortsbezogene Android XR-Erlebnisse erstellen. Zuerst sehen wir uns an, wie Sie mit ARCore die Geopose eines Geräts abrufen. Anschließend sehen Sie, wie die minimalistischen UI-Komponenten von Glimmer über das Visual Positioning System (VPS) an realen Orten verankert werden können. Wir kombinieren diese, um eine einfache, standortbezogene räumliche Umgebung zu erstellen.
Transkript
Hallo zusammen, willkommen zur ersten Session des Android XR-Tracks hier beim Android Developer Summit.
Ja!
Wir freuen uns sehr, dass so viele von euch mehr über Android XR erfahren möchten.
Mein Name ist Yasmine Quintana Evjen. Ich bin hier mit Paul Hoover und Dereck Bridie, die sich im Laufe des Gesprächs zu uns gesellen werden.
In dieser Session geht es um Android XR und darum, wie Sie mit Jetpack Compose Glimmer und ARCore für Jetpack XR räumlich verankerte, reale Erlebnisse erstellen können.
Zuerst möchten wir Android XR kurz vorstellen.
Android XR ist eine neue Plattform, die die Interaktion von Nutzern mit Ihrer App neu definiert. Sie geht über den Bildschirm hinaus und bezieht die Umgebung der Nutzer mit ein.
Wir entwickeln die Plattform so, dass digitale Erlebnisse direkt in die physische Umgebung gebracht werden.
Das können Overlays sein, die auf einen Blick erfassbar sind und die reale Welt erweitern, oder eine unendliche immersive Umgebung.
Es ist dasselbe offene Android-Ökosystem, das wir seit Jahren gemeinsam aufbauen. Jetzt ist die Leinwand so groß wie der Raum und so weit, wie es eure Fantasie zulässt.
XR umfasst eine Vielzahl von Geräten – von intelligenten Brillen, die leichte, erweiterte Funktionen auf Audio- und Display-Brillen ermöglichen, bis hin zu immersiven Headsets und kabelgebundenen XR-Datenbrillen, die Fokus, Produktivität und immersive Unterhaltungsmöglichkeiten bieten.
Das neueste Gerät der Android XR-Familie ist die XREAL AURA, die ab heute erhältlich ist.
Dieses Gerät ist leicht und leistungsstark und ermöglicht XR-Erlebnisse mit der vertrauten Android-Umgebung.
Unsere Vision für die Plattform ist, dass alle, die bereits für Android entwickeln, auch für XR entwickeln können.
Wir möchten es Ihnen so einfach wie möglich machen, Apps für Android XR zu entwickeln. Deshalb können Sie das App-Modell, die Bibliothek und die Tools verwenden, die Sie bereits kennen.
Ihre vorhandene 2D-Android-kompatible App funktioniert mit keinen oder nur wenigen Änderungen auf Android XR-Headsets und kabelgebundenen XR-Datenbrillen.
Und um tolle XR-Erlebnisse zu schaffen, die sich wie zu Hause anfühlen, bieten wir eine Reihe von Bibliotheken, die speziell für die XR-Plattform entwickelt wurden.
Entwickler, die bereits Erfahrungen mit anderen immersiven Plattformen haben, können OpenXR und unsere 3D-Engine-Unterstützung wie Unity, Godot und Unreal verwenden.
Sehen wir uns an, wie Sie mit Android-Bibliotheken entwickeln können.
Wir stellen das Jetpack XR SDK bereit, eine Reihe von Kotlin-Bibliotheken, mit denen Sie Ihre Apps auf XR erweitern können, um immersive und Augmented-Reality-Erlebnisse zu ermöglichen.
Sehen wir uns unsere immersiven Bibliotheken an.
Unsere Jetpack XR-Bibliotheken sind dieses Jahr in die Beta- und stabile Version übergegangen. Sie können also jetzt mit der Entwicklung Ihrer immersiven XR-Erlebnisse beginnen.
Die Wahrnehmungsebene ist ARCore für Jetpack XR.
Diese Bibliothek liefert Informationen über die reale Welt, z. B. wo sich flache Oberflächen wie ein Tisch befinden und wie die Hände der Nutzer positioniert sind.
Sie kann Punkte im 3D-Raum verfolgen und diese Informationen an Apps weitergeben, sofern die entsprechenden Berechtigungen erteilt wurden.
Dann gibt es noch Jetpack XR SceneCore, das einen Szenengraphen zum Platzieren Ihrer räumlichen Inhalte bereitstellt.
Diese Bibliothek kann Entitäten im 3D-Raum darstellen und bietet räumliche Verhaltensweisen für die präzise Platzierung von Szenengrafiken.
Und Jetpack Compose für XR bietet neue Subspace-Kompositionen, die speziell für 3D entwickelt wurden.
Android-Entwickler, die bereits mit Compose-Layouts vertraut sind, z. B. mit dem Erstellen von Zeilen und Spalten, werden das Layouten von räumlichen Benutzeroberflächen als intuitiv empfinden.
Wenn Sie eine räumliche Zeile erstellen, können Sie mehrere räumliche Bereiche nebeneinander anordnen, ohne ihre Position oder Größe manuell berechnen zu müssen.
Mit Subspace-Kompositionen wie einem räumlichen Bereich oder Orbiter können Sie Ihre 2D-Komponenten ganz einfach in diesen neuen 3D-Bereich erweitern.
Und natürlich können Subspace-Composables mehr als nur 2D-Inhalte anzeigen.
Compose for XR unterstützt räumliche Videos sowie 3D-Modelle über die räumliche externe Oberfläche und das räumliche glTF-Modell.
Sehen wir uns nun erweiterte Apps an.
Mit der Jetpack Projected-Bibliothek können Sie Ihre vorhandene mobile App so erweitern, dass sie die Hardware intelligenter Brillen wie Sensoren und Display nutzt.
Und schließlich Jetpack Compose Glimmer, ein UI-Toolkit zum Erstellen von Android XR-Erlebnissen, die für Datenbrillen optimiert sind.
Jetpack Compose Glimmer besteht aus Stilen und sofort einsatzbereiten Komponenten zum Erstellen von XR-Erlebnissen.
Wir haben Glimmer letztes Jahr eingeführt und die Funktionen seitdem kontinuierlich erweitert. Dazu gehört auch ein agentischer Skill, mit dem Sie Ihre Display-Brillen-Apps mit Glimmer erstellen können.
android skills add display-glasses-with-jetpack-compose-glimmerSeit der Einführung haben wir euer Feedback berücksichtigt.
Wir haben gehört, dass Sie sich eine Erweiterung von Jetpack Compose Glimmer über intelligente Brillen hinaus wünschen.
Wir freuen uns, Ihnen mitteilen zu können, dass wir Änderungen vorgenommen haben, um Ihre räumlich verankerten Erlebnisse mit Glimmer besser zu unterstützen. Darauf werden wir später in diesem Vortrag noch näher eingehen.
Unsere Arbeit zur Optimierung von Glimmer begann mit der Erstellung einer neuen Oberfläche für die Anzeige auf einer Vielzahl von XR-Formfaktoren, von einem Display bis hin zu kabelgebundenen XR-Datenbrillen.
Diese neue Oberfläche bietet mehr Flexibilität bei der Anpassung der Benutzeroberfläche.
Und um die Markenidentität Ihrer App zu stärken, haben wir Glimmer-Komponenten benutzerdefinierte Farben hinzugefügt.
Damit können Sie den Stil Ihrer Marke in Ihren XR-Apps zum Ausdruck bringen.
Unsere Jetpack Compose Glimmer-Bibliothek bietet Hilfsfunktionen, mit denen Sie Ihre Zielfarben und Markenfarben in brillenfreundliche Farben umwandeln können.
So soll die Sichtbarkeit auf optischen See-Through-Displays optimiert werden.
Sehen wir uns das einmal genauer an.
Wir möchten die Farbe des fokussierten Buttons für diese Brillen-App ändern. Ich wähle eine meiner Lieblingsfarben aus.
val brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}Wenn die Farbe dem Code hinzugefügt wird, passen die Glimmer-Hilfsfunktionen sie an eine für Brillen geeignete Farbe an, um die Sichtbarkeit zu optimieren.
All dies ist in unserer Jetpack Compose Glimmer-Bibliothek enthalten, damit Sie Inhalte erstellen können, die in verschiedenen Umgebungen gut aussehen.
In Android Studio können Sie mit dem Emulator visualisieren, wie die Benutzeroberfläche Ihrer Brille vor verschiedenen Hintergründen aussieht, z. B. in hellen, dunklen oder unruhigen Umgebungen.
Diese Updates sind nur die Spitze des Eisbergs.
Ok, nein.
Mein Team hat mir gesagt, dass ich damit keinen Lacher ernten werde, aber ich habe trotzdem daran festgehalten.
Jetzt übergebe ich an Paul, der euch mehr über Jetpack Compose Glimmer erzählen wird.
Testen, alles klar!
Ich muss auf den Button „Weiter“ klicken.
Vielen Dank, Yasmine.
Okay.
Wie Yasmine bereits erwähnt hat, bietet Jetpack Compose Glimmer die grundlegenden Bausteine für die Entwicklung von Anwendungen, die auf Display-Brillen zugeschnitten sind.
Unsere Komponenten berücksichtigen Best Practices für optische See-Through-Displays und sind direkt in die APIs integriert. So können Sie als Entwickler ansprechende und funktionale optische See-Through-Erlebnisse erstellen.
Wenn Sie Apps für optische See-Through-Geräte wie dieses entwerfen und entwickeln, müssen Sie einige Dinge beachten.
Erstens ist es ein transparentes Display, d. h. es gibt kein Schwarz.
Wenn die Welt sichtbar ist, ist das Schwarz transparent.
Sie können sich also nicht darauf verlassen, dass dunkle Hintergründe den Kontrast für Ihre Benutzeroberfläche, Ihren Text und Ihre Inhalte beibehalten.
Obwohl Schwarz unsichtbar ist, können Sie damit andere digitale Inhalte verdecken.
Im Glimmer-UI-Framework gibt es eine Tiefen-API, mit der Sie UI-Elemente ganz einfach voneinander trennen und eine Hierarchie erstellen können.
Hier sehen Sie, wie die Tiefe der Karten in diesem Stapel dazu beiträgt, dass sie voneinander getrennt bleiben.
Unsere Experten für Sehkraft haben Zielkontrastverhältnisse für Text und Symbole festgelegt, die bei den meisten Lichtverhältnissen sichtbar sind.
Wie Yasmine gezeigt hat, haben wir diese Funktion in das Framework integriert. Wenn Sie also die Oberflächenfarben anpassen, können Sie sicher sein, dass die Benutzeroberfläche für Ihre Nutzer lesbar ist.
Diese und andere Best Practices haben wir in unsere wachsende Komponentenbibliothek integriert.
Wir haben in letzter Zeit viele neue Komponenten veröffentlicht.
Eine unserer neuesten Komponenten ist die Pager-Komponente mit integrierten flüssigen Bewegungsübergängen und Gesten.
val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}Wenn Sie mit dem horizontalen Pager von Compose vertraut sind, wird Ihnen diese Komponente sehr bekannt vorkommen.
Außerdem haben wir vier neue Kartenvarianten eingeführt, die sich nahtlos in Pager, Stapel und andere Glimmer-UI-Elemente einfügen.
Auf Karten mit vorangestelltem Bild und Karten mit nachgestelltem Bild werden Text und Bilder nebeneinander angezeigt.
Verwenden Sie diese Kartenvarianten, wenn Sie gleich viele Text- und visuelle Informationen haben.
Wir haben die Bildkarte in eine eigene Kartenvariante aufgeteilt.
Diese Option eignet sich am besten, wenn Sie ein großes Bild mit einer einzelnen Textzeile oder Bildunterschrift haben, wie bei dieser Videoauswahl.
Bei der Aktionskartenvariante wird eine einzelne Schaltfläche in eine Karte eingebettet.
Verwenden Sie diese Option, wenn Nutzer genau wissen sollen, was passiert, wenn sie die Karte aktivieren, z. B. in dieser Zielauswahl.
Mit Schaltflächengruppen können Sie viele Schaltflächen auf kleinem Raum unterbringen.
ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}Mit diesem einfachen Code erhalten Sie diese schönen Übergänge, Scrollverhalten, Scrims, die die Ränder verbergen und nur bei Bedarf angezeigt werden, und Eingaben, die automatisch von der Brille an das Steuerelement weitergeleitet werden.
Schaltflächengruppen können auch unsere neuen Symbolschaltflächen und Ein/Aus-Schaltflächen enthalten.
var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Hier sehen Sie alle unsere Schaltflächentypen, die für diese Mediensteuerung verwendet werden.
Und es ist jetzt ganz einfach, die Benutzeroberfläche auf verschiedenen Hintergründen zu testen.
Mit dem Brillen-Emulator können Sie 360°-Fotos einfügen und schwenken, um die Brille vor verschiedenen Hintergründen zu testen, z. B. vor unruhigen, hellen oder dunklen Hintergründen.
Schaltflächengruppen eignen sich hervorragend für Detailansichten wie diese, um Kontextaktionen anzuzeigen.
Wenn Sie auf ein Element tippen, können Sie mithilfe von Übergängen für freigegebene Elemente zu einer detaillierten Ansicht wechseln und dann mit der Systemgeste „Zurück“ zur vorherigen Ansicht zurückkehren.
Sehr schön.
Außerdem haben wir eine Anzeige für die Spracheingabe und Warndialoge hinzugefügt.
Es gibt also viele neue Funktionen.
Nachdem wir uns einige der neuen Funktionen angesehen haben, wollen wir jetzt etwas erstellen.
Glimmer kann nicht nur für die Entwicklung von Smart Glasses, sondern auch für die Entwicklung von Erlebnissen für kabelgebundene XR-Datenbrillen verwendet werden.
Wir möchten, dass Sie Erlebnisse schaffen, die die Welt um Sie herum erweitern, beginnend mit standortbasierten Ankern in der realen Welt.
Stellen Sie sich vor, Sie sind in einer neuen Stadt, vielleicht auf einer Entwicklerkonferenz, und möchten etwas essen.
Sie könnten Ihre bevorzugte Navigations-App bitten, Restaurants in der Nähe und deren Bewertungen zu finden.
Informationen können direkt über den Standort gelegt werden, um Kontext, Informationen und Anleitungen bereitzustellen.
Hier sehen Sie unsere neueste Glimmer-Komponente, die Symbolmarkierung.
Damit kannst du wichtige Elemente in der physischen Welt hervorheben und mit anderen Glimmer-Komponenten wie dieser Karte kombinieren.
In diesem Beispiel werden POIs mithilfe der Google Maps, Places und Geospatial APIs annotiert.
Hey, Dereck, lass uns zeigen, wie das eingerichtet wird.
Fangen wir an.
Okay.
Okay.
Wie Paul schon sagte: Legen wir los.
Wir verwenden die Entwicklerdokumentation auf developer.android.com/xr und sehen uns die Jetpack Compose Glimmer-Komponentenbibliothek an.
Hier finden Sie eine visuelle Übersicht aller Komponenten, die in Glimmer verfügbar sind.
Beginnen wir mit diesem Teil der Benutzeroberfläche, den Paul vorhin gezeigt hat.
Wir verwenden also die Glimmer-UI, um einen räumlichen Indikator und eine Infobox zu erstellen.
Sehen wir uns zuerst die Komponenten an, die wir verwenden werden.
Links sehen Sie eine Symbolmarkierung und rechts eine Karte, die den Ort beschreibt.
Wenn Sie also Android Studio aufrufen, können Sie sich eine Vorschau dieses Bereichs wie bei jeder anderen Compose-Komponente ansehen und Ihre Änderungen in Echtzeit verfolgen.
Wie bereits erwähnt, können Sie sich die Benutzeroberfläche in allen möglichen Hintergrundumgebungen ansehen und prüfen, ob der Kontrast Ihrer Benutzeroberfläche in verschiedenen Szenarien, z. B. in dunklen und hellen Umgebungen, ausreicht.
Nachdem der Canvas festgelegt wurde, erstellen wir eine Zeile, fügen eine Symbolmarkierung mit etwas Abstand und eine Karte mit Beispieltext hinzu.
Das war es auch schon.
Wenn Sie mit der 2D-Vorschau zufrieden sind, können wir mit dem Markieren in der realen Welt beginnen. Dazu verräumlichen wir die Benutzeroberfläche.
Das bedeutet, dass wir es in 3D statt in 2D darstellen.
Räumliche Benutzeroberflächen sind also in Unterbereichen enthalten, die sich in einem 3D-Bereich vor dem Nutzer befinden.
Subspace {
SpatialPanel {
VideoPlayer()
}
}Standardmäßig werden die Inhalte eines Subspace in einer angenehmen Entfernung vom Nutzer platziert.
Bevor wir Ihnen zeigen, wie Sie die Geospatial API verwenden, platzieren wir zuerst etwas in der Nähe.
Die zuvor erwähnte Subspace-Komposition hat einen optionalen Parameter, mit dem Sie ein Ziel angeben können, dem gefolgt werden soll.
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}Wenn Sie etwas an der realen Welt befestigen möchten, erstellen Sie zuerst einen Anker, der von ARCore für Jetpack XR abgerufen wird.
In diesem Beispiel verwende ich die QR-Code-Erkennung.
Damit können Sie QR-Codes lesen und verfolgen, sodass Ihre Inhalte diesem QR-Code im Raum folgen können. Wir hängen die Benutzeroberfläche an, die wir vorhin gesehen haben.
Okay.
Ich habe Ihnen gezeigt, wie Sie digitale Inhalte in der realen Welt in der Nähe platzieren.
Kommen wir zurück zu Pauls Beispiel.
Ich persönlich komme aus den Niederlanden.
Ich kenne mich in Mountain View nicht wirklich aus.
Nach diesem Event möchte ich Ihnen helfen, eine App zu erstellen, mit der Sie interessante Cafés finden können.
Sehen wir uns also an, wie wir unseren Nutzern mit der Geospatial API, die jetzt in ARCore für Jetpack XR enthalten ist, helfen können, welche zu finden.
Die Geospatial API, die ursprünglich für Smartphones eingeführt wurde, ist jetzt auch für Android XR verfügbar.
Dabei werden Daten aus Google Street View mit GPS-Messungen kombiniert, um das Gerät in unterstützten Bereichen zu positionieren.
Auf Smart Glasses kann die Geospatial API also verwendet werden, um den Standort und die Blickrichtung des Nutzers genau zu bestimmen. So sind hochpräzise Anwendungsfälle für die detaillierte Routenführung möglich.
Und auf immersiven Geräten wie kabelgebundenen XR-Brillen können Sie mit der Geospatial API Erlebnisse schaffen, die genau in der realen Welt positioniert sind.
Sie können beispielsweise räumliche Inhalte an Gebäuden verankern oder spezielle Stadtrundgänge erstellen.
Beginnen wir also mit den ersten Schritten zur Verwendung der Geospatial API.
Zuerst erstellen Sie ein Google Cloud Platform-Projekt und konfigurieren die Authentifizierung in Ihrer App.
Wenn die Geospatial API in Ihrer App konfiguriert und aktiviert ist, bitten Sie den Nutzer um die Erlaubnis, seinen genauen Standort abzurufen.
Nachdem Sie die Sitzung für die Verwendung der Geospatial API konfiguriert haben, sind Sie fertig.
Alle Details zur Geospatial API finden Sie in der Entwicklerdokumentation auf der neu gestalteten Android XR-Entwicklerseite.
Beginnen wir also damit, den Standort des Nutzers zu verwenden, um die Places API der Google Maps Platform nach guten Cafés in der Nähe des Nutzers zu fragen.
Zuerst: Wo befindet sich der Nutzer?
Wir bitten die Geospatial API, kontinuierlich Updates zum Standort des Nutzers zu senden.
produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}Wir greifen also über die XR-Sitzung auf das Geospatial-Objekt zu.
Danach warten wir, bis Geospatial einsatzbereit ist, die erforderlichen Sensoren initialisiert und eine Verbindung zur Cloud API hergestellt hat.
Dann warten wir, bis ein bestimmtes Maß an Genauigkeit erreicht ist.
Die Genauigkeit kann sich also verbessern, wenn GPS-Messungen eingehen oder das visuelle Positionierungssystem Übereinstimmungen am Standort des Nutzers findet.
Es ist wichtig, auf eine hohe Genauigkeit zu warten, damit standortbezogene Erlebnisse am richtigen Ort verankert sind und die Ergebnisse aus der Nähe des Nutzers stammen.
Anschließend können wir mit der Places API und den Standortwerten aus der Geospatial API die Suche durchführen.
val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()Wir verwenden also einen SearchNearbyRequest mit der Places API, um nach Orten in der Nähe der zuvor ermittelten Position des Nutzers zu suchen. Wir finden Ergebnisse im Umkreis von 100 m.
Wir rufen die Orts-ID, den Anzeigenamen, die Bewertung und natürlich den Standort des Orts ab.
Anschließend führen wir die Suche mit den angegebenen Parametern aus, einschließlich eines Filters für den Ortstyp.
Das war es zu den Daten. Kehren wir zur Benutzeroberfläche zurück.
Wir müssen also herausfinden, wie wir die Markierung und das Infofeld von vorhin platzieren können. Dazu verwenden wir Georäumliche Anker.
Zurück zum Code: Wir greifen noch einmal über unsere XR-Sitzung auf die Geospatial API zu und erstellen dann einen Georäumlichen Anker mit einem bestimmten Breiten- und Längengrad, den wir zuvor aus den Suchergebnissen erhalten haben.
val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}In diesem Beispiel haben wir die Höhe auf 3 m über dem Gelände an diesen Koordinaten festgelegt. Sie können die Höhe aber auch an unterstützten Dächern festmachen. Das bedeutet, dass der Höhenwert relativ zum Dach des Gebäudes an diesem Standort bestimmt wird.
Sie können den Anker auch mit einer Quaternion drehen, die die Rotationswerte des Ankers angibt.
In diesem Beispiel verwenden wir jedoch die Standardeinstellungen, da wir die Benutzeroberfläche so drehen, dass sie dem Nutzer zugewandt ist.
Anschließend hängen wir die Glimmer-UI von vorhin an diesen Anker an. Damit haben Sie die Bausteine für eine räumlich verankerte Umgebung.
when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}Wir sind davon überzeugt, dass die Geospatial API eine hervorragende Wegfindung ermöglicht. Mit Glimmer können Sie übersichtliche Benutzeroberflächen erstellen, die speziell für Ihre transparenten Displays geeignet sind.
Weitere Informationen zur Geospatial API finden Sie auf der kürzlich aktualisierten Website developer.android.com/xr.
Und jetzt übergebe ich wieder an Yasmine.
In dieser Sitzung haben wir uns einige Funktionen von Android XR angesehen: ARCore für Jetpack XR und Jetpack Compose Glimmer.
Wir sind gespannt, welche neuen Funktionen Android XR für kabelgebundene XR-Datenbrillen bieten wird.
Entwickler erstellen bereits Inhalte für Android XR und wir hoffen, dass wir auch Ihre kreativen Werke im Google Play Store sehen werden.
Für den Einstieg empfehlen wir unsere Entwicklerdokumentation, unsere XR-Experimente und unsere Codelabs.
Wir haben jede Menge tolle XR-Sitzungen, ‑Demos und ‑Workshops für Sie geplant.
Sehen Sie sich also die Videos an und erfahren Sie, wie Sie für Android XR entwickeln und immersive und Augmented-Reality-Inhalte erstellen können.
Im Namen des Android XR-Teams möchte ich mich bei euch allen für eure Teilnahme bedanken. Wir hoffen, dass ihr den restlichen Android Developer Summit genießt.
Also danke dir dafür.
android skills add display-glasses-with-jetpack-compose-glimmerval brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Subspace {
SpatialPanel {
VideoPlayer()
}
}val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}