Android XR

Créer des expériences ancrées dans le monde réel pour les lunettes XR filaires

Haut-parleurs

À propos

À propos de l'intervention

Ne vous contentez plus de l'espace de l'écran et ancrez vos applications dans le monde réel avec Android XR. Cette session vous apprend à créer des expériences Android XR géospatiales à l'aide de Jetpack Compose Glimmer et de l'API ARCore Geospatial. Nous allons commencer par voir comment obtenir la position géospatiale d'un appareil avec ARCore. Vous verrez ensuite comment les composants d'interface utilisateur minimalistes de Glimmer peuvent être ancrés à des lieux réels via le système de positionnement visuel (VPS). Nous allons les combiner pour créer une expérience spatiale simple et sensible à la localisation.

Résumé

  • Android XR intègre des expériences numériques dans des environnements physiques sur une variété d'appareils, des lunettes connectées aux lunettes XR filaires. Les applications 2D existantes compatibles avec Android fonctionnent sur les casques XR et les lunettes XR filaires avec un minimum de modifications.
  • Jetpack Compose Glimmer fournit des composants et des styles adaptés aux écrans optiques transparents. Les fonctions d'assistance intégrées ajustent les couleurs de la marque pour les adapter aux lunettes, afin de maintenir la visibilité et le contraste dans différentes conditions d'éclairage.
  • La bibliothèque Glimmer ajoute de nouveaux composants tels que des pagers et des groupes de boutons. Une API de profondeur permet de séparer les éléments empilés sur les écrans transparents où le noir est transparent.
  • Les composables Subspace placent les interfaces dans un espace 3D et peuvent suivre les ancres ARCore via une cible de suivi, comme un QR code suivi.
  • L'API Geospatial dans ARCore combine les données Street View et les mesures GPS pour positionner précisément les appareils dans les zones compatibles. Vous pouvez associer des composants Glimmer à des ancres géospatiales réelles à l'aide des coordonnées issues des requêtes de l'API Places.

Ressources

Gemini Notebook

Thèmes

  • android-xr
  • jetpack-compose
  • glimmer
  • arcore
  • geospatial-api
  • réalité augmentée

Transcription

Présentation d'Android XR

  • Bonjour à tous et bienvenue à votre première session sur le parcours Android XR ici au Sommet des développeurs Android.

  • Ouais !

  • Nous sommes ravis de voir que vous êtes si nombreux à vous intéresser à Android XR.

  • Je m'appelle Yasmine Quintana Evjen. Je suis accompagnée de Paul Hoover et Dereck Bridie, qui se joindront à nous au cours de la conversation.

  • Cette session est consacrée à Android XR et à la façon dont vous pouvez créer des expériences ancrées dans l'espace et le monde réel avec Jetpack Compose Glimmer et ARCore pour Jetpack XR.

  • Mais d'abord, présentons brièvement Android XR.

  • Android XR est une nouvelle plate-forme qui redéfinit la façon dont les utilisateurs interagissent avec votre application, en allant au-delà de l'écran et en s'étendant à l'espace qui les entoure.

  • Nous concevons la plate-forme de manière à intégrer les expériences numériques directement dans l'environnement physique.

  • Qu'il s'agisse de superpositions d'informations qui améliorent la présence dans le monde réel ou d'un environnement immersif infini.

  • Il s'agit du même écosystème Android ouvert que nous développons ensemble depuis des années, mais désormais, la toile est aussi grande que la pièce et aussi vaste que votre imagination peut l'emmener.

  • Pour nous, la XR englobe un large éventail d'appareils, allant des lunettes connectées, qui permettent des expériences légères et augmentées sur des lunettes audio et avec affichage, aux casques immersifs et aux lunettes XR filaires, qui offrent des fonctionnalités de concentration, de productivité et de divertissement immersif.

  • Le dernier appareil de la famille Android XR est le XREAL AURA, disponible à l'achat dès aujourd'hui.

  • Cet appareil est léger et puissant, et permet de profiter d'expériences XR avec la familiarité d'Android.

  • Notre vision pour la plate-forme est la suivante : si vous développez déjà pour Android, vous êtes prêt à développer pour la XR.

  • Nous voulons vous permettre de développer facilement sur Android XR en utilisant le même modèle d'application, la même bibliothèque et les mêmes outils que ceux que vous connaissez déjà.

  • Votre application 2D existante compatible avec Android fonctionnera sur les casques Android XR et les lunettes XR filaires, avec peu ou pas de modifications.

SDK Jetpack XR et outils pour les développeurs

  • Pour créer des expériences XR exceptionnelles et parfaitement adaptées, nous fournissons un ensemble de bibliothèques spécialement conçues pour la plate-forme XR.

  • Si vous avez l'habitude de créer des expériences sur d'autres plates-formes immersives, vous pouvez utiliser OpenXR et nos moteurs 3D compatibles, comme Unity, Godot et Unreal.

  • Parlons de la compilation avec des bibliothèques Android.

  • Nous fournissons le SDK Jetpack XR, un ensemble de bibliothèques Kotlin qui vous aident à étendre vos applications à la XR via des expériences immersives et augmentées.

  • Examinons nos bibliothèques immersives.

  • Nos bibliothèques Jetpack XR sont passées en version bêta et stable cette année, ce qui vous donne la confiance nécessaire pour commencer à créer vos expériences XR immersives.

  • La couche de perception est ARCore pour Jetpack XR.

  • Cette bibliothèque fournit des informations sur le monde réel, comme l'emplacement des surfaces planes (une table, par exemple) et la position des mains des utilisateurs.

  • Il peut suivre des points dans un espace 3D et fournit ces informations aux applications, à condition qu'elles disposent des autorisations nécessaires.

  • Ensuite, Jetpack XR SceneCore fournit un graphique de scène pour placer votre contenu spatial.

  • Cette bibliothèque est capable de présenter des entités dans un espace 3D et fournit des comportements spatiaux pour un placement précis du graphe de scène.

  • Jetpack Compose pour XR fournit de nouveaux composables de sous-espace conçus spécialement pour la 3D.

  • Les développeurs Android qui connaissent déjà les mises en page Compose, comme la création avec des lignes et des colonnes, trouveront la mise en page de l'UI spatiale intuitive.

  • En créant une ligne spatiale, vous pouvez disposer de manière déclarative plusieurs panneaux spatiaux côte à côte sans avoir à calculer manuellement leur position ou leur taille.

  • À l'aide de composables de sous-espace, comme un panneau spatial ou un orbiteur, vous pouvez facilement étendre vos composants 2D à ce nouvel espace 3D.

  • Bien entendu, les composables Subspace ne se contentent pas d'afficher du contenu 2D.

  • Compose pour XR est compatible avec les vidéos spatiales ainsi qu'avec les modèles 3D via la surface externe spatiale et le modèle glTF spatial.

Créer une UI avec Jetpack Compose Glimmer

  • Parlons maintenant des applications augmentées.

  • La bibliothèque Jetpack Projected vous permet d'améliorer votre application mobile existante pour utiliser du matériel de lunettes connectées, comme des capteurs et un écran.

  • Enfin, Jetpack Compose Glimmer, un kit d'UI permettant de créer des expériences Android XR optimisées pour les lunettes.

  • Jetpack Compose Glimmer se compose de styles et de composants prêts à l'emploi pour créer vos expériences XR.

  • Nous avons lancé Glimmer l'année dernière et avons continué à développer ses fonctionnalités, y compris une compétence agentive pour vous aider à créer vos applications de lunettes avec affichage avec Glimmer.

    android skills add display-glasses-with-jetpack-compose-glimmer
  • Depuis le lancement, nous avons tenu compte de vos commentaires.

  • Vous nous avez demandé d'étendre Jetpack Compose Glimmer au-delà des lunettes connectées.

  • Nous sommes heureux d'annoncer que nous avons apporté des modifications pour mieux prendre en charge vos expériences ancrées dans l'espace avec Glimmer, que nous aborderons plus en détail plus tard dans cette présentation.

  • Pour optimiser Glimmer, nous avons commencé par créer une surface d'affichage adaptée à différents facteurs de forme XR, des écrans aux lunettes XR filaires.

  • L'ajout de cette nouvelle surface vous offre plus de flexibilité pour personnaliser votre UI.

  • Pour que votre application se démarque encore plus, nous avons ajouté des couleurs personnalisées aux composants Glimmer.

  • Utilisez-les pour exprimer le style de votre marque dans vos applications XR.

  • Notre bibliothèque Jetpack Compose Glimmer fournit des fonctions d'assistance qui convertissent vos couleurs cibles et les couleurs de votre marque en couleurs adaptées aux lunettes.

  • Cela permet d'optimiser la visibilité sur les écrans optiques transparents.

  • Voyons cela en action.

  • Nous voulons modifier la couleur du bouton sélectionné pour cette application de lunettes. Je vais choisir l'une de mes couleurs préférées.

    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 */
       }
    }
  • Notez que lorsque la couleur est ajoutée au code, les fonctions d'assistance Glimmer l'ajustent pour qu'elle soit adaptée aux lunettes et offre une visibilité optimale.

  • Tout cela est intégré à notre bibliothèque Jetpack Compose Glimmer, ce qui vous permet de créer des expériences qui s'affichent correctement dans différents environnements.

  • Dans Android Studio, vous pouvez utiliser l'émulateur pour visualiser l'apparence de l'UI de vos lunettes sur différents arrière-plans, tels que des environnements clairs, sombres ou chargés.

  • Ces nouveautés ne sont qu'un début.

  • OK, non.

  • Mon équipe m'a dit que ça ne ferait rire personne, mais j'ai quand même gardé cette blague.

  • Je vais maintenant laisser la parole à Paul, qui va vous en dire plus sur Jetpack Compose Glimmer.

Principes de conception de l'UI pour les lunettes avec affichage

  • C'est parti pour les tests !

  • Je dois appuyer sur le bouton "Suivant".

  • Merci, Yasmine.

  • Très bien.

  • Comme l'a dit Yasmine, Jetpack Compose Glimmer fournit les composants de base pour développer des applications adaptées aux lunettes avec affichage.

  • Nos composants intègrent les bonnes pratiques conçues pour les écrans optiques transparents, et nous les avons intégrés directement dans les API pour vous, afin de permettre à tous les développeurs de créer des expériences d'optique transparente esthétiques et fonctionnelles.

  • Lorsque vous concevez et créez des applications pour des appareils optiques transparents comme celui-ci, vous devez garder quelques points à l'esprit.

  • Tout d'abord, il s'agit d'un écran transparent, ce qui signifie qu'il n'y a pas de noir.

  • Lorsque le monde est visible, le noir est transparent.

  • Vous ne pouvez donc pas compter sur les arrière-plans sombres pour maintenir le contraste de votre UI, de votre texte et de votre contenu.

  • Même si le noir est invisible, vous pouvez l'utiliser pour masquer d'autres contenus numériques.

  • Dans le framework d'interface utilisateur Glimmer, nous disposons d'une API de profondeur qui vous permet de séparer facilement les éléments d'interface utilisateur les uns des autres et de donner une impression de hiérarchie.

  • Ici, vous pouvez voir comment la profondeur des cartes de cette pile les aide à rester séparées les unes des autres.

  • Nos scientifiques spécialisés dans la vision ont fourni des ratios de contraste cibles pour le texte et les icônes qui sont visibles dans la plupart des conditions d'éclairage.

  • Comme Yasmine l'a montré, nous pouvons intégrer cela ou nous l'avons intégré au framework afin que, lorsque vous personnalisez les couleurs de surface, vous puissiez être sûr que votre interface sera lisible pour vos utilisateurs.

  • Nous avons intégré ces bonnes pratiques et d'autres dans notre bibliothèque de composants en pleine expansion.

  • Nous avons récemment lancé de nombreux nouveaux composants.

  • L'un de nos derniers ajouts est le composant de pagination, qui intègre des transitions de mouvement et des gestes fluides.

    val pagerState =
      rememberGlimmerPagerState(pageCount = { 10 })
    
    GlimmerHorizontalPager(pagerState) { page ->
       /* Card Content */
    }
  • Si vous connaissez le composant HorizontalPager de Compose, vous ne serez pas dépaysé.

  • Nous avons également introduit quatre nouvelles variantes de fiches conçues pour s'intégrer parfaitement aux pagers, aux piles et à d'autres éléments de l'UI Glimmer.

  • Les fiches avec image au début et les fiches avec image à la fin affichent du texte et des images l'un à côté de l'autre.

  • Utilisez donc ces variantes de fiches lorsque vous avez une quantité égale de texte et d'informations visuelles.

  • Nous avons séparé la fiche d'image dans sa propre variante de fiche.

  • Il est préférable d'utiliser ce composant lorsque vous avez une grande image avec peut-être une seule ligne de texte ou une légende, comme ce sélecteur de vidéo.

  • La variante de fiche d'action intègre un seul bouton dans une fiche.

  • Utilisez cette option lorsque vous souhaitez que les utilisateurs sachent exactement ce qui se passera lorsqu'ils activeront la fiche, comme dans ce sélecteur de destination.

  • Les groupes de boutons vous permettent de regrouper de nombreux boutons dans un petit espace.

    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") }
    }
  • Avec ce simple code, vous obtenez de superbes transitions, des comportements de défilement, des voiles qui masquent les bords et ne s'affichent que lorsque cela est nécessaire, et une entrée qui est automatiquement acheminée des lunettes vers la commande.

  • Les groupes de boutons peuvent également contenir nos nouveaux boutons d'icône et boutons d'activation.

    var buttonChecked by remember { mutableStateOf(false) }
    
    ToggleButton(
      checked = buttonChecked,
      leadingIcon = { Icon(FavoriteIcon) },
      onCheckedChange = { buttonChecked = it }
    ) {
      Text(if (buttonChecked) "On" else "Off")
    }
  • Vous pouvez voir ici tous nos types de boutons utilisés pour créer cette commande multimédia.

  • Il est désormais facile de tester votre UI sur différents arrière-plans.

  • L'émulateur de lunettes vous permet d'insérer des photos à 360° et de faire un panoramique pour tester l'affichage sur différents arrière-plans, chargés, clairs, sombres, etc.

  • Les groupes de boutons sont parfaits pour afficher des actions contextuelles dans une vue détaillée comme celle-ci.

  • En appuyant sur l'écran, vous pouvez utiliser des transitions d'éléments partagés pour accéder à un état de visionneuse détaillé, puis utiliser le geste Retour du système pour revenir à la vue précédente.

  • C'est très bien.

  • Nous avons également ajouté un indicateur de saisie vocale et des boîtes de dialogue d'alerte.

  • Donc, oui, beaucoup de nouveautés.

  • Maintenant que nous avons vu certaines des nouveautés, créons quelque chose.

Présentation des ancres basées sur la localisation

  • En plus de créer des lunettes connectées, nous pouvons utiliser Glimmer pour créer des expériences pour les lunettes XR filaires.

  • Nous voulons que vous créiez des expériences qui enrichissent le monde qui vous entoure, en commençant par des ancres basées sur des lieux réels.

  • Imaginez que vous êtes dans une nouvelle ville, peut-être pour assister à une conférence de développeurs, et que vous souhaitez trouver un endroit où manger.

  • Vous pouvez demander à votre application de navigation préférée de trouver des restaurants à proximité et d'afficher leurs notes.

  • Les informations peuvent être superposées directement sur l'emplacement, fournissant ainsi du contexte, des renseignements et des conseils.

  • Ici, vous pouvez voir notre dernier composant Glimmer, appelé "Icon Marker".

  • Il vous permet de mettre en évidence des éléments clés du monde physique et de les associer à d'autres composants Glimmer, comme cette fiche.

  • Dans cet exemple, elle annote des points d'intérêt à l'aide des API Google Maps, Places et Geospatial.

  • Dereck, montrons-leur comment configurer cela.

  • C'est parti.

  • Très bien.

  • Très bien.

  • Comme Paul l'a dit, passons à la création.

  • Nous allons donc utiliser la documentation pour les développeurs sur developer.android.com/xr et examiner la bibliothèque de composants Jetpack Compose Glimmer.

  • Vous pourrez ainsi trouver un aperçu visuel de tous les composants disponibles sur Glimmer.

  • Commençons par l'élément d'interface utilisateur que Paul a montré plus tôt.

  • Nous allons donc utiliser l'UI Glimmer pour créer un indicateur spatial et une boîte d'informations.

  • Commençons par identifier les composants que nous allons utiliser.

  • À gauche, vous verrez un repère d'icône, et à droite, nous utiliserons une fiche qui décrira le lieu.

  • Si vous accédez à Android Studio, vous pouvez prévisualiser ce volet comme n'importe quel autre composant Compose et voir vos modifications en temps réel.

  • Comme mentionné précédemment, vous pouvez prévisualiser l'UI dans différents types d'environnements d'arrière-plan et vous assurer que le contraste de votre UI est suffisant dans plusieurs types de scénarios, comme les environnements sombres et clairs.

  • Maintenant que le canevas est défini, nous allons créer une ligne, y placer un repère d'icône avec un certain espacement, et une fiche avec un exemple de texte.

  • Et voilà, c'est tout.

  • Si l'aperçu 2D vous convient, nous pouvons commencer à marquer un élément dans le monde réel en spatialisant l'UI.

  • Cela signifie que nous allons l'agencer en 3D au lieu de la 2D.

  • Les interfaces utilisateur spatiales sont donc contenues dans des sous-espaces, qui sont des espaces 3D situés devant l'utilisateur.

    Subspace {
      SpatialPanel {
        VideoPlayer()
      }
    }
  • Par défaut, un sous-espace dispose son contenu à une distance confortable de l'utilisateur.

  • Avant de vous montrer comment utiliser l'API Geospatial, plaçons d'abord un élément à proximité.

  • Le composable Subspace dont j'ai parlé plus tôt comporte un paramètre facultatif qui vous permet de spécifier une cible à suivre.

    val state by
      qrCode.state.collectAsState()
    Subspace(FollowTarget.anchor(anchor)) {
      SpatialPanel {
        Row {
          IndicatorDot()
          Spacer()
          QrCodeCard(state)
        }
      }
    }
  • Pour associer un élément au monde réel, vous devez d'abord créer une ancre obtenue à partir d'ARCore pour Jetpack XR.

  • Dans cet exemple, j'utilise la fonctionnalité de reconnaissance de code QR.

  • Cela vous permettra de lire et de suivre les QR codes, afin que votre contenu puisse suivre ce QR code dans l'espace. Nous associerons l'UI que nous avons vue précédemment.

Intégration de l'API Geospatial et de Google Maps Platform

  • OK.

  • Je vous ai montré comment placer du contenu numérique dans le monde réel à proximité.

  • Revenons à l'exemple de Paul.

  • Personnellement, je viens des Pays-Bas.

  • Je ne connais pas vraiment Mountain View.

  • Après cet événement, je veux vous aider à créer une application qui vous aidera à trouver des cafés sympas.

  • Voyons comment nous pouvons aider nos utilisateurs à en trouver grâce à l'API Geospatial, qui se trouve désormais dans ARCore pour Jetpack XR.

  • L'API Geospatial, initialement lancée sur les smartphones, est désormais disponible sur Android XR.

  • Elle utilise les données de Google Street View et les combine avec les mesures GPS pour positionner l'appareil dans les zones compatibles.

  • Ainsi, sur des lunettes connectées, l'API Geospatial peut être utilisée pour déterminer avec précision la position et le cap de l'utilisateur, et permet des cas d'utilisation de navigation détaillée de haute précision.

  • Sur les appareils immersifs tels que les lunettes XR filaires, l'API Geospatial vous permet de créer des expériences positionnées avec précision dans le monde réel.

  • Par exemple, vous pouvez ancrer du contenu spatial sur des bâtiments ou créer des visites guidées spécialisées de villes.

  • Commençons par l'API Geospatial en suivant ces trois étapes.

  • La première consiste à créer un projet Google Cloud Platform et à configurer l'authentification dans votre application.

  • Ensuite, une fois l'API Geospatial configurée et activée dans votre application, vous demanderez à l'utilisateur l'autorisation de récupérer sa position avec une précision élevée.

  • Ensuite, après avoir configuré la session pour utiliser l'API Geospatial, vous êtes prêt.

  • Vous trouverez donc tous les détails sur notre documentation pour les développeurs concernant l'API Geospatial sur notre page Android XR pour les développeurs, qui vient d'être actualisée.

  • Commençons par utiliser la position de l'utilisateur pour demander à l'API Places de Google Maps Platform de trouver de bons cafés à proximité.

  • Tout d'abord, où se trouve l'utilisateur ?

  • Nous allons demander à l'API Geospatial de recevoir des mises à jour continues sur la position de l'utilisateur.

    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)
    
    }
  • Nous allons donc accéder à l'objet géospatial via la session XR.

  • Ensuite, nous attendrons que l'API Geospatial soit opérationnelle, le temps qu'elle initialise les capteurs nécessaires et se connecte à l'API Cloud.

  • Nous attendrons ensuite d'atteindre un certain niveau de précision.

  • Les niveaux de précision peuvent donc s'améliorer à mesure que les mesures GPS sont reçues ou lorsque le système de positionnement visuel trouve des correspondances à l'emplacement de l'utilisateur.

  • Il est important d'attendre un niveau de haute précision pour s'assurer que les expériences de localisation sont ancrées au bon endroit et que les résultats proviennent de la zone géographique de l'utilisateur.

  • Nous sommes alors prêts à effectuer la recherche avec l'API Places en utilisant les valeurs de localisation de l'API Geospatial.

    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()
  • Nous allons donc utiliser un SearchNearbyRequest avec l'API Places pour rechercher des lieux autour de la position de l'utilisateur que nous avons obtenue précédemment, et nous trouverons des résultats dans un rayon de 100 m.

  • Nous allons obtenir l'ID du lieu, son nom à afficher, sa note et, bien sûr, sa position.

  • Enfin, nous effectuerons la recherche avec les paramètres spécifiés, y compris un filtre de type de lieu.

  • Voilà pour les données. Revenons à l'interface utilisateur.

  • Nous devons donc trouver comment placer notre repère et notre boîte d'informations de tout à l'heure. Pour cela, nous allons utiliser des ancres géospatiales.

  • Revenons au code. Une fois de plus, nous allons accéder à l'API Geospatial à l'aide de notre session XR, puis nous allons créer une ancre géospatiale à l'aide d'une latitude et d'une longitude spécifiques obtenues précédemment à partir des résultats de recherche.

    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()
     )
    }
  • Dans cet exemple, nous avons spécifié une altitude de 3 m au-dessus du terrain à ces coordonnées, mais vous pouvez également l'associer à des toits compatibles. Cela signifie que la valeur d'altitude sera déterminée par rapport au toit du bâtiment à cet emplacement.

  • Vous pouvez également faire pivoter l'ancrage à l'aide d'un quaternion, qui spécifie les valeurs de rotation de l'ancrage.

  • Toutefois, nous utiliserons les valeurs par défaut dans cet exemple, car nous ferons pivoter l'UI pour qu'elle soit face à l'utilisateur.

  • Ensuite, nous associerons l'UI Glimmer de tout à l'heure à cette ancre, ce qui vous donnera les éléments de base d'une expérience ancrée dans l'espace.

    when (anchorResult) {
     is AnchorCreateSuccess ->
       Subspace(FollowTarget.anchor(anchorResult.anchor)) {
         SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
           PlaceIndicator(place)
         }
       }
    
     else ->
       Log.e("Demo", "Failed to create anchor $anchorResult")
    }
  • Nous pensons donc que l'API Geospatial peut permettre de créer d'excellentes expériences d'orientation, et que concevoir avec Glimmer vous aidera à créer des expériences utilisateur faciles à consulter, spécialement conçues pour vos écrans transparents.

  • Pour en savoir plus sur l'API Geospatial, consultez la page developer.android.com/xr, qui a été récemment mise à jour.

  • Je vais maintenant laisser la parole à Yasmine pour conclure.

Conclusion et ressources pour les développeurs

  • Dans cette session, nous avons abordé quelques fonctionnalités d'Android XR : ARCore pour Jetpack XR et Jetpack Compose Glimmer.

  • Nous sommes impatients de découvrir les nouvelles fonctionnalités qu'Android XR apportera aux lunettes XR filaires.

  • Les développeurs créent déjà des applications pour Android XR, et nous espérons voir vos créations sur le Google Play Store.

  • Pour vous aider à vous lancer, consultez notre documentation pour les développeurs, laissez-vous inspirer par nos expériences XR et lancez-vous avec les ateliers de programmation.

  • Nous avons prévu de nombreuses sessions, démonstrations et ateliers XR pour vous tous.

  • Alors, restez à l'écoute et découvrez comment créer des expériences immersives et augmentées pour Android XR.

  • Au nom de l'équipe Android XR, merci à tous d'être ici. Nous espérons que vous apprécierez le reste du Sommet des développeurs Android.

  • Merci.

Code

Extraits de code

Extrait de code shell à 04:39 dans "Créer une UI avec Jetpack Compose Glimmer"
android skills add display-glasses-with-jetpack-compose-glimmer
Extrait de code Kotlin à 05:49 dans "Créer une UI avec Jetpack Compose Glimmer"
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 */
   }
}
Extrait de code Kotlin à 08:37 dans "Principes de conception d'UI pour les lunettes avec affichage"
val pagerState =
  rememberGlimmerPagerState(pageCount = { 10 })

GlimmerHorizontalPager(pagerState) { page ->
   /* Card Content */
}
Extrait de code Kotlin à 09:50 dans "Principes de conception d'UI pour les lunettes avec affichage"
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") }
}
Extrait Kotlin à 10:13 dans "Principes de conception d'UI pour les lunettes avec affichage"
var buttonChecked by remember { mutableStateOf(false) }

ToggleButton(
  checked = buttonChecked,
  leadingIcon = { Icon(FavoriteIcon) },
  onCheckedChange = { buttonChecked = it }
) {
  Text(if (buttonChecked) "On" else "Off")
}
Extrait de code Kotlin à 13:55 dans "Présentation des ancres géospatiales"
Subspace {
  SpatialPanel {
    VideoPlayer()
  }
}
Extrait de code Kotlin à 14:16 dans "Présentation des ancres géolocalisées"
val state by
  qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
  SpatialPanel {
    Row {
      IndicatorDot()
      Spacer()
      QrCodeCard(state)
    }
  }
}
Extrait Kotlin à 16:43 dans "Intégration de l'API Geospatial et de Google Maps Platform"
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)

}
Extrait Kotlin à 17:27 dans "Intégration de l'API Geospatial et de Google Maps Platform"
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()
Extrait Kotlin à 18:09 dans "Intégration de l'API Geospatial et de Google Maps Platform"
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()
 )
}
Extrait Kotlin à 18:53 dans "Intégration de l'API Geospatial et de Google Maps Platform"
when (anchorResult) {
 is AnchorCreateSuccess ->
   Subspace(FollowTarget.anchor(anchorResult.anchor)) {
     SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
       PlaceIndicator(place)
     }
   }

 else ->
   Log.e("Demo", "Failed to create anchor $anchorResult")
}