Starszy menedżer produktu
Wyjdź poza przestrzeń ekranu i zakotwicz aplikacje w świecie rzeczywistym dzięki Androidowi XR. Podczas tej sesji dowiesz się, jak tworzyć aplikacje na Androida XR z uwzględnieniem danych geoprzestrzennych za pomocą Jetpack Compose Glimmer i interfejsu Geospatial API ARCore. Zaczniemy od omówienia, jak uzyskać pozycję geoprzestrzenną urządzenia za pomocą ARCore. Następnie zobaczysz, jak minimalistyczne komponenty interfejsu Glimmer można zakotwiczyć w lokalizacjach w świecie rzeczywistym za pomocą systemu pozycjonowania wizualnego (VPS). Połączymy je, aby stworzyć proste, uwzględniające lokalizację środowisko przestrzenne.
Transkrypcja
Cześć wszystkim, witamy na pierwszej sesji dotyczącej Androida XR na Android Dev Summit.
Tak!
Cieszymy się, że tak wielu z Was interesuje się Androidem XR.
Nazywam się Yasmine Quintana Evjen, a razem ze mną są Paul Hoover i Dereck Bridie, którzy dołączą do nas w trakcie rozmowy.
Tematem tej sesji jest Android XR oraz to, jak za pomocą Jetpack Compose Glimmer i ARCore dla Jetpack XR tworzyć rozwiązania zakotwiczone przestrzennie w świecie rzeczywistym.
Najpierw jednak krótko przedstawimy Androida XR.
Android XR to nowa platforma, która zmienia sposób, w jaki użytkownicy wchodzą w interakcję z aplikacją, wykraczając poza ekran i obejmując przestrzeń wokół nich.
Projektujemy platformę tak, aby przenosić cyfrowe doświadczenia bezpośrednio do środowiska fizycznego.
Może to być nakładka, która wzbogaca rzeczywistość, lub nieskończone, immersyjne środowisko.
To ten sam otwarty ekosystem Androida, który budujemy razem od lat, ale teraz przestrzeń jest tak duża jak pokój i tak rozległa, jak tylko pozwala na to wyobraźnia.
XR to dla nas całe spektrum urządzeń – od inteligentnych okularów, które zapewniają lekkie, rozszerzone wrażenia dzięki funkcjom audio i wyświetlaczowi, po immersyjne gogle i przewodowe okulary XR, które zapewniają skupienie, produktywność i możliwości immersyjnej rozrywki.
Najnowszym urządzeniem z rodziny Androida XR są okulary XREAL AURA, które można już kupić.
To urządzenie jest lekkie i wydajne, dzięki czemu umożliwia korzystanie z XR w znanym środowisku Androida.
Nasza wizja platformy jest taka, że jeśli już tworzysz aplikacje na Androida, możesz też tworzyć aplikacje na XR.
Chcemy ułatwić Ci tworzenie aplikacji na Androida XR, korzystając z tego samego modelu aplikacji, biblioteki i narzędzi, które już znasz.
Twoja dotychczasowa aplikacja 2D zgodna z Androidem będzie działać na goglach z Androidem XR i przewodowych okularach XR bez żadnych modyfikacji lub z niewielkimi zmianami.
Aby umożliwić tworzenie niesamowitych środowisk XR, które będą działać naturalnie, udostępniamy zestaw bibliotek stworzonych specjalnie na platformę XR.
Deweloperzy, którzy są przyzwyczajeni do tworzenia treści na innych platformach immersyjnych, mogą korzystać z OpenXR i naszego wsparcia dla silników 3D, takich jak Unity, Godot i Unreal.
Porozmawiajmy o tworzeniu aplikacji za pomocą bibliotek Androida.
Udostępniamy pakiet SDK Jetpack XR, czyli zestaw bibliotek Kotlin, który pomaga rozszerzyć aplikacje na XR w trybie immersyjnym i rzeczywistości rozszerzonej.
Przyjrzyjmy się naszym bibliotekom immersyjnym.
W tym roku nasze biblioteki Jetpack XR osiągnęły wersję beta i stabilną, co daje Ci pewność, że możesz zacząć tworzyć immersyjne środowiska XR.
Warstwa percepcji to ARCore dla Jetpack XR.
Ta biblioteka dostarcza informacji o świecie rzeczywistym, np. o tym, gdzie znajdują się płaskie powierzchnie, takie jak stół, i jak ułożone są dłonie użytkowników.
Może śledzić punkty w przestrzeni 3D i udostępniać te informacje aplikacjom, jeśli oczywiście mają one odpowiednie uprawnienia.
Jest też Jetpack XR SceneCore, który udostępnia graf sceny do umieszczania treści przestrzennych.
Ta biblioteka umożliwia prezentowanie elementów w przestrzeni 3D i zapewnia zachowania przestrzenne, które pozwalają na precyzyjne umieszczanie elementów w grafie sceny.
Z kolei Jetpack Compose for XR udostępnia nowe elementy kompozycyjne podprzestrzeni stworzone specjalnie z myślą o 3D.
Programiści aplikacji na Androida, którzy znają już układy Compose, takie jak tworzenie z użyciem wierszy i kolumn, uznają, że układanie interfejsu przestrzennego jest intuicyjne.
Tworząc wiersz przestrzenny, możesz deklaratywnie ułożyć wiele paneli przestrzennych obok siebie bez konieczności ręcznego obliczania ich pozycji lub rozmiaru.
Za pomocą komponentów podprzestrzeni, takich jak panel przestrzenny lub orbiter, możesz łatwo rozszerzyć komponenty 2D na tę nową przestrzeń 3D.
Oczywiście elementy kompozycyjne podprzestrzeni mogą nie tylko wyświetlać treści 2D.
Compose for XR obsługuje filmy przestrzenne i modele 3D za pomocą przestrzennej powierzchni zewnętrznej i przestrzennego modelu glTF.
Porozmawiajmy teraz o aplikacjach rozszerzonych.
Dzięki bibliotece Jetpack Projected możesz ulepszyć istniejącą aplikację mobilną, aby korzystała z inteligentnych okularów, takich jak czujniki i wyświetlacz.
Na koniec Jetpack Compose Glimmer, czyli zestaw narzędzi do tworzenia interfejsu użytkownika, który umożliwia tworzenie aplikacji na Androida XR zoptymalizowanych pod kątem okularów.
Jetpack Compose Glimmer zawiera style i gotowe do użycia komponenty do tworzenia aplikacji XR.
W zeszłym roku wprowadziliśmy Glimmer i nadal rozwijamy jego możliwości, w tym umiejętność agentową, która pomaga tworzyć aplikacje na okulary z wyświetlaczem za pomocą Glimmer.
android skills add display-glasses-with-jetpack-compose-glimmerOd momentu wprowadzenia tej funkcji słuchamy Waszych opinii.
Otrzymaliśmy od Was prośby o rozszerzenie Jetpack Compose Glimmer poza inteligentne okulary.
Z przyjemnością informujemy, że wprowadziliśmy zmiany, które ułatwią korzystanie z funkcji zakotwiczonych przestrzennie w Glimmer. Omówimy je później w tej prezentacji.
Prace nad optymalizacją Glimmer rozpoczęliśmy od utworzenia nowej powierzchni do wyświetlania na różnych urządzeniach XR, od wyświetlacza po przewodowe okulary XR.
Dodanie tej nowej platformy zapewnia większą elastyczność w dostosowywaniu interfejsu.
Aby zwiększyć rozpoznawalność marki Twojej aplikacji, dodaliśmy spersonalizowane kolory do komponentów Glimmer.
Używaj ich, aby wyrazić styl swojej marki w aplikacjach XR.
Nasza biblioteka Jetpack Compose Glimmer udostępnia funkcje pomocnicze, które konwertują kolory docelowe i kolory marki na kolory bezpieczne dla okularów.
Ma to na celu zapewnienie optymalnej widoczności na wyświetlaczach optycznych.
Zobaczmy, jak to działa w praktyce.
Chcemy zmienić kolor przycisku, na którym jest ustawiony fokus, w tej aplikacji do okularów. Wybiorę jeden z moich ulubionych kolorów.
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 */
}
}Zauważ, że gdy kolor zostanie dodany do kodu, funkcje pomocnicze Glimmer dostosują go do koloru bezpiecznego dla okularów, aby zapewnić optymalną widoczność.
Wszystko to jest wbudowane w naszą bibliotekę Jetpack Compose Glimmer, dzięki czemu możesz tworzyć interfejsy, które wyglądają świetnie w różnych środowiskach.
W Android Studio możesz użyć emulatora, aby zobaczyć, jak interfejs okularów będzie wyglądać na różnych tła, np. w jasnym, ciemnym lub ruchliwym otoczeniu.
Te zmiany to dopiero początek.
OK, nie.
Mój zespół powiedział mi, że nikt się z tego nie zaśmieje, ale i tak go zachowałem.
Teraz Paul opowie Wam więcej o Jetpack Compose Glimmer.
Testuję, wszystko w porządku.
Muszę kliknąć przycisk Dalej.
Dziękuję, Yasmine.
OK.
Jak wspomniała Yasmine, Jetpack Compose Glimmer zapewnia podstawowe elementy do tworzenia aplikacji na okulary z wyświetlaczem.
Nasze komponenty integrują sprawdzone metody opracowane dla wyświetlaczy optycznych, a my wbudowaliśmy je bezpośrednio w interfejsy API, aby umożliwić wszystkim deweloperom tworzenie pięknych i funkcjonalnych rozwiązań optycznych.
Podczas projektowania i tworzenia aplikacji na urządzenia z optycznym systemem przeziernym, takie jak to, musisz pamiętać o kilku kwestiach.
Po pierwsze, jest to wyświetlacz przezroczysty, co oznacza, że nie ma czerni.
Gdy świat jest widoczny, czerń jest przezroczysta.
Nie możesz więc liczyć na to, że ciemne tło zapewni kontrast dla interfejsu, tekstu i treści.
Mimo że kolor czarny jest niewidoczny, możesz go używać do zasłaniania innych treści cyfrowych.
W interfejsie Glimmer mamy interfejs Depth API, który umożliwia łatwe oddzielanie elementów interfejsu od siebie i tworzenie poczucia hierarchii.
Tutaj możesz zobaczyć, jak głębia kart w tym stosie pomaga im zachować odrębność.
Nasi naukowcy zajmujący się widzeniem podali docelowe współczynniki kontrastu dla tekstu i ikon, które są widoczne w większości warunków oświetleniowych.
Jak pokazała Yasmine, możemy to wbudować lub wbudowaliśmy to w platformę, aby po dostosowaniu kolorów powierzchni można było mieć pewność, że interfejs będzie czytelny dla użytkowników.
Te i inne sprawdzone metody uwzględniliśmy w naszej rozszerzającej się bibliotece komponentów.
Niedawno wprowadziliśmy wiele nowych komponentów.
Jednym z naszych najnowszych dodatków jest komponent pagera z wbudowanymi płynnymi przejściami i gestami.
val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}Jeśli znasz poziomy pager Compose, ten komponent będzie Ci bardzo dobrze znany.
Wprowadziliśmy też 4 nowe warianty kart, które można bezproblemowo integrować z paginatorami, stosami i innymi elementami interfejsu Glimmer.
Karty z obrazem na początku i karty z obrazem na końcu zawierają tekst i obrazy obok siebie.
Używaj tych wariantów kart, gdy masz taką samą ilość tekstu i informacji wizualnych.
Karta z obrazem została wydzielona jako osobny wariant karty.
Najlepiej używać go, gdy masz duży obraz z jednym wierszem tekstu lub podpisem, jak w przypadku tego selektora filmów.
Wariant karty działania zawiera pojedynczy przycisk.
Używaj tego, gdy chcesz, aby użytkownicy wiedzieli dokładnie, co się stanie, gdy aktywują kartę, np. w tym selektorze miejsca docelowego.
Grupy przycisków umożliwiają umieszczenie wielu przycisków na małej przestrzeni.
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") }
}Dzięki temu prostemu kodowi uzyskasz piękne przejścia, zachowania przewijania, scrimy, które ukrywają krawędzie i wyświetlają się tylko wtedy, gdy są potrzebne, oraz dane wejściowe, które są automatycznie kierowane z okularów do elementu sterującego.
Grupy przycisków mogą też zawierać nasze nowe przyciski ikon i przyciski przełączania.
var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Tutaj możesz zobaczyć wszystkie typy przycisków użyte do utworzenia tych opcji sterowania multimediami.
Teraz możesz łatwo testować interfejs na różnych tła.
Emulator okularów pozwala na wstawianie zdjęć sferycznych i przesuwanie ich, dzięki czemu można przetestować okulary na różnych tłach, tłach z dużą ilością elementów, jasnych i ciemnych.
Grupy przycisków świetnie nadają się do wyświetlania czynności kontekstowych w widoku szczegółowym, takim jak ten.
Po kliknięciu możesz użyć przejść ze wspólnymi elementami, aby przejść do szczegółowego stanu przeglądarki, a następnie użyć systemowego gestu wstecz, aby wrócić do poprzedniego widoku.
Bardzo miło.
Dodaliśmy też wskaźnik wprowadzania głosowego i okna alertów.
Tak więc mamy dużo nowości.
Teraz, gdy już poznaliśmy niektóre z nowych funkcji, zbudujmy coś.
Oprócz tworzenia inteligentnych okularów możemy używać Glimmer do tworzenia funkcji na przewodowe okulary XR.
Chcemy, abyście tworzyli rozwiązania, które wzbogacają otaczający nas świat, zaczynając od kotwic opartych na lokalizacji w świecie rzeczywistym.
Wyobraź sobie, że jesteś w nowym mieście, na przykład na konferencji dla deweloperów, i chcesz znaleźć coś do jedzenia.
Możesz poprosić ulubioną aplikację do nawigacji o znalezienie pobliskich restauracji i ich ocen.
Informacje mogą być nakładane bezpośrednio na lokalizację, co zapewnia kontekst, dane i wskazówki.
Tutaj możesz zobaczyć nasz najnowszy komponent Glimmer o nazwie Icon Marker.
Pozwala wyróżnić kluczowe elementy w świecie fizycznym i połączyć je z innymi komponentami Glimmer, takimi jak ta karta.
W tym przykładzie dodaje adnotacje do ciekawych miejsc za pomocą interfejsów Mapy Google, Miejsc i Geospatial API.
Dereck, pokażmy, jak to skonfigurować.
Zróbmy to.
OK.
OK.
Jak wspomniał Paul, zacznijmy tworzyć.
Skorzystamy z dokumentacji dla deweloperów na stronie developer.android.com/xr i przyjrzymy się bibliotece komponentów Glimmer w Jetpack Compose.
Znajdziesz tam wizualny przegląd wszystkich komponentów dostępnych w Glimmer.
Zacznijmy od tego elementu interfejsu, który Paul pokazał wcześniej.
Użyjemy więc interfejsu Glimmer, aby utworzyć wskaźnik przestrzenny i pole informacyjne.
Zacznijmy od określenia komponentów, których będziemy używać.
Po lewej stronie zobaczysz znacznik ikony, a po prawej – kartę z opisem miejsca.
Jeśli przejdziesz do Android Studio, możesz wyświetlić podgląd tego panelu tak samo jak każdego innego komponentu Compose i zobaczyć zmiany w czasie rzeczywistym.
Jak wspomniano wcześniej, możesz wyświetlić podgląd interfejsu w różnych środowiskach tła i upewnić się, że kontrast interfejsu jest wystarczający w różnych scenariuszach, np. w ciemnym i jasnym otoczeniu.
Po skonfigurowaniu obszaru roboczego utworzymy wiersz, umieścimy w nim znacznik ikony z odstępami i kartę z przykładowym tekstem.
I to wszystko.
Jeśli podgląd 2D Ci odpowiada, możemy zacząć oznaczać coś w świecie rzeczywistym. Zrobimy to, nadając interfejsowi charakter przestrzenny.
Oznacza to, że układ będzie trójwymiarowy, a nie dwuwymiarowy.
Interfejsy przestrzenne są więc zawarte w podprzestrzeniach, czyli przestrzeniach 3D przed użytkownikiem.
Subspace {
SpatialPanel {
VideoPlayer()
}
}Domyślnie podprzestrzeń rozmieszcza zawartość w wygodnej odległości od użytkownika.
Zanim pokażemy Ci, jak korzystać z interfejsu Geospatial API, umieśćmy coś w pobliżu.
Komponent podprzestrzeni, o którym mówiłem wcześniej, ma opcjonalny parametr, który pozwala określić cel śledzenia.
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}Aby dołączyć coś do świata rzeczywistego, najpierw utwórz kotwicę uzyskaną z ARCore dla Jetpack XR.
W tym przykładzie używam funkcji rozpoznawania kodu QR.
Dzięki temu możesz odczytywać i śledzić kody QR, dzięki czemu Twoje treści mogą podążać za kodem QR w przestrzeni, a my dołączymy interfejs, który widzieliśmy wcześniej.
OK.
Pokazałem, jak umieszczać treści cyfrowe w świecie rzeczywistym w pobliżu.
Wróćmy do przykładu Pawła.
Osobiście pochodzę z Holandii.
Nie znam zbyt dobrze Mountain View.
Po tym wydarzeniu chcę pomóc Ci stworzyć aplikację, która pomoże Ci znaleźć ciekawe kawiarnie.
Zobaczmy, jak możemy pomóc użytkownikom znaleźć niektóre z nich za pomocą interfejsu Geospatial API, który jest teraz dostępny w ARCore for Jetpack XR.
Dlatego interfejs Geospatial API, który pierwotnie został wprowadzony na smartfonach, już jest dostępny również na Androidzie XR.
Wykorzystuje dane z Google Street View i łączy je z pomiarami GPS, aby określić pozycję urządzenia na obsługiwanych obszarach.
Dzięki temu w inteligentnych okularach interfejs Geospatial API może służyć do dokładnego określania lokalizacji i kierunku użytkownika, co umożliwia precyzyjne korzystanie ze szczegółowych wskazówek dojazdu.
Z kolei na urządzeniach immersyjnych, takich jak przewodowe okulary XR, interfejs Geospatial API umożliwia tworzenie treści, które są dokładnie pozycjonowane w świecie rzeczywistym.
Możesz na przykład zakotwiczyć treści przestrzenne na budynkach lub utworzyć specjalistyczne wycieczki po mieście.
Zacznijmy od 3 kroków, które pozwolą Ci rozpocząć korzystanie z interfejsu Geospatial API.
Najpierw utworzysz projekt Google Cloud Platform i skonfigurujesz uwierzytelnianie w aplikacji.
Następnie, gdy interfejs Geospatial API zostanie skonfigurowany i włączony w aplikacji, poprosisz użytkownika o zgodę na pobieranie jego lokalizacji z dużą dokładnością.
Następnie skonfiguruj sesję, aby korzystała z interfejsu Geospatial API.
Wszystkie szczegóły dotyczące interfejsu Geospatial API znajdziesz w dokumentacji dla deweloperów na naszej nowo odświeżonej stronie dla deweloperów Androida XR.
Zacznijmy od użycia lokalizacji użytkownika, aby poprosić interfejs Places API z Google Maps Platform o znalezienie świetnych kawiarni w pobliżu użytkownika.
Po pierwsze, gdzie znajduje się użytkownik?
Poprosimy interfejs Geospatial API o ciągłe aktualizowanie lokalizacji użytkownika.
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)
}Dlatego uzyskamy dostęp do obiektu geoprzestrzennego przez sesję XR.
Następnie poczekamy, aż Geospatial zacznie działać, zainicjuje niezbędne czujniki i połączy się z interfejsem Cloud API.
Następnie poczekamy na osiągnięcie określonego poziomu dokładności.
Dzięki temu poziom dokładności może się poprawić, gdy pojawią się pomiary GPS lub gdy system pozycjonowania wizualnego znajdzie dopasowania w lokalizacji użytkownika.
Oczekiwanie na Wysoką dokładność jest ważne, aby mieć pewność, że funkcje związane z lokalizacją są zakotwiczone we właściwym miejscu, a wyniki pochodzą z pobliskiego obszaru użytkownika.
Następnie możemy przeprowadzić wyszukiwanie za pomocą interfejsu Places API, używając wartości lokalizacji z interfejsu Geospatial API.
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()Dlatego użyjemy SearchNearbyRequest z interfejsem Places API, aby wyszukać miejsca wokół lokalizacji użytkownika, którą uzyskaliśmy wcześniej, i znaleźć wyniki w promieniu 100 metrów.
Pobierzemy identyfikator miejsca, jego wyświetlaną nazwę, ocenę i oczywiście lokalizację.
Na koniec przeprowadzimy wyszukiwanie z określonymi parametrami, w tym z filtrem typu miejsca.
To wszystko, jeśli chodzi o dane. Wróćmy do interfejsu.
Musimy więc wymyślić, jak umieścić nasz znacznik i pole informacyjne z wcześniejszego etapu. W tym celu użyjemy kotwic geoprzestrzennych.
Wracając do kodu, ponownie uzyskamy dostęp do interfejsu Geospatial API za pomocą sesji XR, a następnie utworzymy kotwicę geoprzestrzenną, używając określonej szerokości i długości geograficznej, które zostały wcześniej uzyskane z wyników wyszukiwania.
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()
)
}W tym przykładzie określiliśmy wysokość na 3 metry nad terenem przy tych współrzędnych, ale można też dołączyć do obsługiwanych dachów, co oznacza, że wartość wysokości zostanie określona względem dachu budynku w tej lokalizacji.
Możesz też obrócić kotwicę za pomocą kwaternionu, który określa wartości obrotu kotwicy.
W tym przykładzie użyjemy jednak wartości domyślnych, ponieważ interfejs będzie się obracać w stronę użytkownika.
Następnie do tej kotwicy dołączymy interfejs Glimmer, co zapewni podstawowe elementy do stworzenia środowiska zakotwiczonego przestrzennie.
when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}Uważamy, że interfejs Geospatial API może ułatwić znajdowanie drogi, a projektowanie z wykorzystaniem Glimmer pomoże tworzyć interfejsy użytkownika, które będą łatwe do odczytania i będą przeznaczone specjalnie na przezroczyste wyświetlacze.
Więcej informacji o interfejsie Geospatial API znajdziesz na niedawno zaktualizowanej stronie developer.android.com/xr.
Teraz oddaję głos Yasmine, która zakończy prezentację.
Podczas tej sesji omówiliśmy kilka funkcji Androida XR: ARCore dla Jetpack XR i Jetpack Compose Glimmer.
Z niecierpliwością czekamy na nowe funkcje, które Android XR wprowadzi na przewodowych okularach XR.
Deweloperzy już tworzą aplikacje na Androida XR. Mamy nadzieję, że Twoje kreatywne dzieło pojawi się w Sklepie Google Play.
Aby zacząć, zapoznaj się z naszą dokumentacją dla deweloperów, zainspiruj się naszymi eksperymentami z XR i wypróbuj ćwiczenia z programowania.
Przygotowaliśmy dla Was mnóstwo świetnych sesji, prezentacji i warsztatów dotyczących XR.
Zapraszamy do oglądania i poznawania sposobów tworzenia aplikacji na Androida XR w trybie immersyjnym i rzeczywistości rozszerzonej.
W imieniu zespołu Androida XR dziękuję wszystkim za obecność i życzę miłego spędzenia czasu podczas Android Dev Summit.
Dziękuję.
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")
}