Utiliser la bibliothèque d'applications Android for Cars

La bibliothèque d'applications Android for Cars vous permet d'intégrer vos applications de navigation, de point d'intérêt (POI) et d'IoT (Internet des objets) à votre voiture. Pour ce faire, il fournit un ensemble de modèles conçus pour répondre aux normes de distraction du conducteur et prend en compte des détails tels que la variété des facteurs d'écran de la voiture et les modalités d'entrée.

Ce guide présente les principales fonctionnalités et concepts de la bibliothèque, et vous explique comment configurer une application de base.

Avant de commencer

  1. Consultez les pages Concevoir pour la conduite sur la bibliothèque d'applications pour voitures.
  2. Passez en revue les termes et concepts clés dans la section suivante.
  3. Familiarisez-vous avec l'interface utilisateur du système Android Auto et la conception d'Android Automotive OS.
  4. Consultez les notes de version.
  5. Consultez les exemples.

Termes et concepts clés

Modèles et modèles
L'interface utilisateur est représentée par un graphique d'objets de modèle qui peuvent être organisés ensemble de différentes manières, comme le permet le modèle auquel ils appartiennent. Les modèles sont un sous-ensemble des modèles pouvant servir de racine dans ces graphiques. Les modèles incluent les informations à afficher à l'utilisateur sous forme de texte et d'images, ainsi que des attributs permettant de configurer des aspects de l'apparence visuelle de ces informations (par exemple, les couleurs de texte ou les tailles d'image). L'hôte convertit les modèles en vues conçues pour répondre aux normes de distraction du conducteur et s'occupe des détails tels que la variété des facteurs d'écran de voiture et les modalités d'entrée.
Hôte
L'hôte est le composant backend qui implémente les fonctionnalités proposées par les API de la bibliothèque afin que votre application puisse s'exécuter dans la voiture. Les responsabilités de l'hôte vont de la découverte de votre application et de la gestion de son cycle de vie à la conversion de vos modèles en vues et à la notification de votre application des interactions utilisateur. Sur les appareils mobiles, cet hôte est implémenté par Android Auto. Sur Android Automotive OS, cet hôte est installé en tant qu'application système.
Restrictions concernant les modèles
Différents modèles appliquent des restrictions au contenu de leurs modèles. Par exemple, les modèles de liste limitent le nombre d'éléments pouvant être présentés à l'utilisateur. Les modèles sont également soumis à des restrictions concernant la manière dont ils peuvent être connectés pour former le flux d'une tâche. Par exemple, l'application ne peut pas insérer plus de cinq modèles dans la pile d'écrans. Pour en savoir plus, consultez la section Restrictions concernant les modèles.
Screen
Screen est une classe fournie par la bibliothèque que les applications implémentent pour gérer l'interface utilisateur présentée à l'utilisateur. Un Screen possède un cycle de vie et fournit le mécanisme permettant à l'application d'envoyer le modèle à afficher lorsque l'écran est visible. Les instances Screen peuvent également être transmises et supprimées d'une pile Screen, ce qui garantit qu'elles respectent les restrictions de flux de modèle.
CarAppService
CarAppService est une classe Service abstraite que votre application doit implémenter et exporter pour être découverte et gérée par l'hôte. Le CarAppService de votre application est chargé de valider qu'une connexion hôte peut être fiable à l'aide de createHostValidator, puis de fournir des instances Session pour chaque connexion à l'aide de onCreateSession.
Session

Session est une classe abstraite que votre application doit implémenter et renvoyer à l'aide de CarAppService.onCreateSession. Il sert de point d'entrée pour afficher des informations sur l'écran de la voiture. Il dispose d'un cycle de vie qui indique l'état actuel de votre application sur l'écran de la voiture, par exemple lorsque votre application est visible ou masquée.

Lorsqu'un Session est démarré, par exemple lorsque l'application est lancée pour la première fois, l'hôte demande à l'Screen initial de s'afficher à l'aide de la méthode onCreateScreen.

Installer la bibliothèque d'applications pour voitures

Consultez la page de version de la bibliothèque Jetpack pour savoir comment l'ajouter à votre application.

Configurer les fichiers manifestes de votre application

Avant de pouvoir créer votre application pour voitures, configurez les fichiers manifestes de votre application comme suit.

Déclarer votre CarAppService

L'hôte se connecte à votre application via votre implémentation CarAppService. Vous déclarez ce service dans votre fichier manifeste pour permettre à l'hôte de découvrir et de se connecter à votre application.

Vous devez également déclarer la catégorie de votre application dans l'élément <category> du filtre d'intent de votre application. Pour connaître les valeurs autorisées pour cet élément, consultez la liste des catégories d'applications compatibles.

L'extrait de code suivant montre comment déclarer un service d'application pour voitures pour une application de point d'intérêt dans votre fichier manifeste:

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
        <category android:name="androidx.car.app.category.POI"/>
      </intent-filter>
    </service>

    ...
<application>

Catégories d'applications compatibles

Déclarez la catégorie de votre application en ajoutant une ou plusieurs des valeurs de catégorie suivantes dans le filtre d'intent lorsque vous déclarez votre CarAppService, comme décrit dans la section précédente:

Consultez la page Qualité des applications Android pour les voitures pour obtenir une description détaillée de chaque catégorie et des critères auxquels les applications doivent répondre pour y appartenir.

Spécifier le nom et l'icône de l'application

Vous devez spécifier un nom et une icône d'application que l'hôte peut utiliser pour représenter votre application dans l'UI du système.

Vous pouvez spécifier le nom et l'icône de l'application utilisés pour la représenter à l'aide des attributs label et icon de votre CarAppService:

...
<service
   android:name=".MyCarAppService"
   android:exported="true"
   android:label="@string/my_app_name"
   android:icon="@drawable/my_app_icon">
   ...
</service>
...

Si le libellé ou l'icône ne sont pas déclarés dans l'élément <service>, l'hôte utilise les valeurs spécifiées pour l'élément <application>.

Définir un thème personnalisé

Pour définir un thème personnalisé pour votre application pour voiture, ajoutez un élément <meta-data> dans votre fichier manifeste, comme suit:

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Ensuite, déclarez votre ressource de style pour définir les attributs suivants pour le thème de votre application pour voitures personnalisée:

<resources>
  <style name="MyCarAppTheme">
    <item name="carColorPrimary">@layout/my_primary_car_color</item>
    <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item>
    <item name="carColorSecondary">@layout/my_secondary_car_color</item>
    <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item>
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

Niveau d'API de Car App

La bibliothèque d'applications pour voitures définit ses propres niveaux d'API afin que vous puissiez savoir quelles fonctionnalités de la bibliothèque sont compatibles avec l'hôte de modèle sur un véhicule. Pour récupérer le niveau d'API Car App le plus élevé accepté par un hôte, utilisez la méthode getCarAppApiLevel().

Déclarez le niveau d'API Car App minimal compatible avec votre application dans votre fichier AndroidManifest.xml:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

Consultez la documentation de l'annotation RequiresCarApi pour savoir comment assurer la rétrocompatibilité et déclarer le niveau d'API minimal requis pour utiliser une fonctionnalité. Pour connaître le niveau d'API requis pour utiliser une fonctionnalité spécifique de la bibliothèque d'applications pour voitures, consultez la documentation de référence sur CarAppApiLevels.

Créer votre CarAppService et votre session

Votre application doit étendre la classe CarAppService et implémenter sa méthode onCreateSession, qui renvoie une instance Session correspondant à la connexion actuelle à l'hôte:

Kotlin

class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}

Java

public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

L'instance Session est chargée de renvoyer l'instance Screen à utiliser la première fois que l'application est démarrée:

Kotlin

class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen(carContext)
    }
    ...
}

Java

public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen(getCarContext());
    }
    ...
}

Pour gérer les scénarios où votre application pour voiture doit démarrer à partir d'un écran qui n'est pas l'écran d'accueil ou de destination de votre application, comme la gestion des liens profonds, vous pouvez pré-ensemencer une pile "Retour" d'écrans à l'aide de ScreenManager.push avant de revenir depuis onCreateScreen. Le pré-ensemencement permet aux utilisateurs de revenir aux écrans précédents à partir du premier écran de votre application.

Créer votre écran de démarrage

Vous créez les écrans affichés par votre application en définissant des classes qui étendent la classe Screen et en implémentant sa méthode onGetTemplate, qui renvoie l'instance Template représentant l'état de l'UI à afficher sur l'écran de la voiture.

L'extrait de code suivant montre comment déclarer un Screen qui utilise un modèle PaneTemplate pour afficher une chaîne "Hello world!" simple:

Kotlin

class HelloWorldScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {
        val row = Row.Builder().setTitle("Hello world!").build()
        val pane = Pane.Builder().addRow(row).build()
        return PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build()
    }
}

Java

public class HelloWorldScreen extends Screen {
    @NonNull
    @Override
    public Template onGetTemplate() {
        Row row = new Row.Builder().setTitle("Hello world!").build();
        Pane pane = new Pane.Builder().addRow(row).build();
        return new PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build();
    }
}

Classe CarContext

La classe CarContext est une sous-classe ContextWrapper accessible à vos instances Session et Screen. Il permet d'accéder aux services de voiture, tels que ScreenManager pour gérer la pile d'écran, AppManager pour les fonctionnalités générales liées aux applications, telles que l'accès à l'objet Surface pour des cartes de dessin et NavigationManager utilisé par les applications de navigation par étapes pour communiquer des métadonnées de navigation et d'autres événements liés à la navigation avec l'hôte.

Consultez Accéder aux modèles de navigation pour obtenir une liste complète des fonctionnalités de bibliothèque disponibles pour les applications de navigation.

CarContext propose également d'autres fonctionnalités, comme la possibilité de charger des ressources drawable à l'aide de la configuration depuis l'écran de la voiture, de lancer une application dans la voiture à l'aide d'intents et d'indiquer si votre application doit afficher sa carte en thème sombre.

Implémenter la navigation à l'écran

Les applications présentent souvent un certain nombre d'écrans différents, chacun pouvant utiliser des modèles différents que l'utilisateur peut parcourir lorsqu'il interagit avec l'interface affichée à l'écran.

La classe ScreenManager fournit une pile d'écrans que vous pouvez utiliser pour pousser des écrans pouvant être affichés automatiquement lorsque l'utilisateur sélectionne un bouton Retour sur l'écran de la voiture ou utilise le bouton Retour physique disponible dans certaines voitures.

L'extrait suivant montre comment ajouter une action "Retour" à un modèle de message, ainsi qu'une action qui affiche un nouvel écran lorsque l'utilisateur la sélectionne:

Kotlin

val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()

Java

MessageTemplate template = new MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        new Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener(
                () -> getScreenManager().push(new NextScreen(getCarContext())))
            .build())
    .build();

L'objet Action.BACK est un Action standard qui appelle automatiquement ScreenManager.pop. Ce comportement peut être remplacé à l'aide de l'instance OnBackPressedDispatcher disponible dans CarContext.

Pour que l'application puisse être utilisée en toute sécurité en conduisant, la pile d'écrans peut avoir une profondeur maximale de cinq écrans. Pour en savoir plus, consultez la section Restrictions concernant les modèles.

Actualiser le contenu d'un modèle

Votre application peut demander l'invalidation du contenu d'un Screen en appelant la méthode Screen.invalidate. L'hôte rappelle ensuite la méthode Screen.onGetTemplate de votre application pour récupérer le modèle avec les nouveaux contenus.

Lors de l'actualisation d'un Screen, il est important de comprendre le contenu spécifique du modèle qui peut être mis à jour afin que l'hôte ne comptabilise pas le nouveau modèle dans le quota de modèles. Pour en savoir plus, consultez la section Restrictions concernant les modèles.

Nous vous recommandons de structurer vos écrans de manière à ce qu'il existe une mise en correspondance individuelle entre un Screen et le type de modèle qu'il renvoie via son implémentation onGetTemplate.

Dessiner des cartes

Les applications de navigation et de points d'intérêt (POI) qui utilisent les modèles suivants peuvent dessiner des cartes en accédant à un Surface:

Template Autorisation de modèle Conseils sur les catégories
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES Navigation
MapWithContentTemplate androidx.car.app.NAVIGATION_TEMPLATES OU
androidx.car.app.MAP_TEMPLATES
Navigation, Points d'intérêt, Météo
MapTemplate (obsolète) androidx.car.app.NAVIGATION_TEMPLATES Navigation
PlaceListNavigationTemplate (obsolète) androidx.car.app.NAVIGATION_TEMPLATES Navigation
RoutePreviewNavigationTemplate (obsolète) androidx.car.app.NAVIGATION_TEMPLATES Navigation

Déclarer l'autorisation de surface

En plus de l'autorisation requise pour le modèle que votre application utilise, votre application doit déclarer l'autorisation androidx.car.app.ACCESS_SURFACE dans son fichier AndroidManifest.xml pour accéder à la surface:

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
  ...
</manifest>

Accéder à la surface

Pour accéder à l'Surface fournie par l'hôte, vous devez implémenter un SurfaceCallback et fournir cette implémentation au service de voiture AppManager. Le Surface actuel est transmis à votre SurfaceCallback dans le paramètre SurfaceContainer des rappels onSurfaceAvailable() et onSurfaceDestroyed().

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

Java

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

Comprendre la zone visible de la surface

L'hôte peut dessiner des éléments d'interface utilisateur pour les modèles situés au-dessus de la carte. L'hôte communique la zone de la surface qui sera non masquée et entièrement visible par l'utilisateur en appelant la méthode SurfaceCallback.onVisibleAreaChanged. En outre, pour minimiser le nombre de modifications, l'hôte appelle la méthode SurfaceCallback.onStableAreaChanged avec le plus petit rectangle, qui est toujours visible en fonction du modèle actuel.

Par exemple, lorsqu'une application de navigation utilise le NavigationTemplate avec une bande d'actions en haut, celle-ci peut se masquer lorsque l'utilisateur n'a pas interagi avec l'écran depuis un certain temps afin de libérer de l'espace pour la carte. Dans ce cas, un rappel de onStableAreaChanged et onVisibleAreaChanged est effectué avec le même rectangle. Lorsque la bande d'actions est masquée, seul onVisibleAreaChanged est appelé avec la plus grande zone. Si l'utilisateur interagit avec l'écran, seul onVisibleAreaChanged est appelé avec le premier rectangle.

Prendre en charge le thème sombre

Les applications doivent redessiner leur carte sur l'instance Surface avec les couleurs sombres appropriées lorsque l'hôte détermine que les conditions le justifient, comme décrit dans la section Qualité des applications Android pour les voitures.

Pour décider si vous devez dessiner une carte sombre, vous pouvez utiliser la méthode CarContext.isDarkMode. Chaque fois que l'état du thème sombre change, vous recevez un appel de Session.onCarConfigurationChanged.

Permettre aux utilisateurs d'interagir avec votre carte

Lorsque vous utilisez les modèles suivants, vous pouvez permettre aux utilisateurs d'interagir avec les cartes que vous dessinez, par exemple en leur permettant de voir différentes parties d'une carte en effectuant des zooms et en passant en mode panoramique.

Template Interactivité prise en charge depuis le niveau d'API de Car App
NavigationTemplate 2
PlaceListNavigationTemplate (obsolète) 4
RoutePreviewNavigationTemplate (obsolète) 4
MapTemplate (obsolète) 5 (introduction du modèle)
MapWithContentTemplate 7 (introduction of template)

Implémenter des rappels d'interactivité

L'interface SurfaceCallback propose plusieurs méthodes de rappel que vous pouvez implémenter pour ajouter de l'interactivité aux cartes créées avec les modèles de la section précédente:

Interaction Méthode SurfaceCallback Prise en charge depuis le niveau d'API de Car App
Appuyer onClick 5
Pincer pour zoomer onScale 2
Faire glisser d'un simple geste onScroll 2
Faire glisser d'un simple geste vif onFling 2
Appuyer deux fois onScale (avec facteur de scaling déterminé par l'hôte du modèle) 2
Geste de rotation en mode panoramique onScroll (avec facteur de distance déterminé par l'hôte du modèle) 2

Ajouter une bande d'actions de la carte

Ces modèles peuvent comporter une bande d'actions pour les actions associées à la carte, telles que le zoom avant et arrière, le recentrage, l'affichage d'une boussole et toute autre action que vous choisissez d'afficher. La bande d'actions sur la carte peut comporter jusqu'à quatre boutons ne contenant qu'une icône, qui peuvent être actualisés sans affecter la profondeur de la tâche. Elle est masquée pendant l'état inactif et réapparaît à l'état actif.

Pour recevoir des rappels d'interactivité sur la carte, vous devez ajouter un bouton Action.PAN dans la bande d'actions de la carte. Lorsque l'utilisateur appuie sur le bouton panoramique, l'hôte passe en mode panoramique, comme décrit dans la section suivante.

Si votre application omet le bouton Action.PAN dans la bande d'actions de la carte, elle ne reçoit pas les entrées utilisateur provenant des méthodes SurfaceCallback, et l'hôte quittera tout mode panoramique précédemment activé.

Sur un écran tactile, le bouton panoramique n'est pas affiché.

Comprendre le mode panoramique

En mode panoramique, l'hôte du modèle traduit les entrées utilisateur des appareils d'entrées non tactiles, tels que les contrôleurs rotatifs et les pavés tactiles dans les méthodes SurfaceCallback appropriées. Répondez à l'action de l'utilisateur visant à ouvrir ou quitter le mode panoramique à l'aide de la méthode setPanModeListener dans le NavigationTemplate.Builder. L'hôte peut masquer d'autres composants d'interface utilisateur dans le modèle lorsque l'utilisateur est en mode panoramique.

Interagir avec l'utilisateur

Votre application peut interagir avec l'utilisateur à l'aide de modèles semblables à ceux d'une application mobile.

Gérer les entrées utilisateur

Votre application peut répondre à l'entrée utilisateur en transmettant les écouteurs appropriés aux modèles qui les prennent en charge. L'extrait de code suivant montre comment créer un modèle Action qui définit un OnClickListener qui appelle une méthode définie par le code de votre application:

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

Java

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

La méthode onClickNavigate peut ensuite démarrer l'application de navigation par défaut pour voiture à l'aide de la méthode CarContext.startCarApp:

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

Java

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

Pour en savoir plus sur le démarrage d'applications, y compris sur le format de l'intent ACTION_NAVIGATE, consultez la section Démarrer une application pour voiture avec un intent.

Certaines actions, comme celles qui nécessitent d'inviter l'utilisateur à poursuivre l'interaction sur ses appareils mobiles, ne sont autorisées que lorsque la voiture est à l'arrêt. Vous pouvez utiliser ParkedOnlyOnClickListener pour implémenter ces actions. Si la voiture n'est pas garée, l'hôte indique à l'utilisateur que l'action n'est pas autorisée dans ce cas. Si la voiture est à l'arrêt, le code s'exécute normalement. L'extrait de code suivant montre comment utiliser ParkedOnlyOnClickListener pour ouvrir un écran de paramètres sur l'appareil mobile:

Kotlin

val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()

Java

Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();

Afficher les notifications

Les notifications envoyées à l'appareil mobile ne s'affichent sur l'écran de la voiture que si elles sont étendues avec un CarAppExtender. Certains attributs de notification, tels que le titre du contenu, le texte, l'icône et les actions, peuvent être définis dans CarAppExtender, ce qui remplace les attributs de la notification lorsqu'ils s'affichent sur l'écran de la voiture.

L'extrait de code suivant montre comment envoyer une notification à l'écran de la voiture qui affiche un titre différent de celui affiché sur l'appareil mobile:

Kotlin

val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()

Java

Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

Les notifications peuvent affecter les éléments suivants de l'interface utilisateur:

  • Une notification prioritaire peut s'afficher à l'utilisateur.
  • Une entrée peut être ajoutée dans le centre de notifications, avec un badge visible dans le rail si vous le souhaitez.
  • Pour les applications de navigation, la notification peut s'afficher dans le widget de rail, comme décrit dans la section Notifications de guidage.

Vous pouvez choisir de configurer les notifications de votre application pour qu'elles affectent chacun de ces éléments d'interface utilisateur à l'aide de la priorité de la notification, comme décrit dans la documentation CarAppExtender.

Si NotificationCompat.Builder.setOnlyAlertOnce est appelé avec la valeur true, une notification de priorité élevée ne s'affiche en tant que notification prioritaire qu'une seule fois.

Pour en savoir plus sur la conception des notifications de votre application pour voitures, consultez le guide Google Design for Driving sur les notifications.

Afficher les toasts

Votre application peut afficher un toast à l'aide de CarToast, comme illustré dans cet extrait:

Kotlin

CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()

Java

CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();

Demander des autorisations

Si votre application a besoin d'accéder à des données ou à des actions restreintes (par exemple, la localisation), les règles standards des autorisations Android s'appliquent. Pour demander une autorisation, vous pouvez utiliser la méthode CarContext.requestPermissions().

L'avantage d'utiliser CarContext.requestPermissions() par rapport aux API Android standards est que vous n'avez pas besoin de lancer votre propre Activity pour créer la boîte de dialogue d'autorisations. De plus, vous pouvez utiliser le même code à la fois sur Android Auto et sur Android Automotive OS, au lieu de créer des flux dépendants de la plate-forme.

Mettre en forme la boîte de dialogue des autorisations sur Android Auto

Sur Android Auto, la boîte de dialogue d'autorisations de l'utilisateur s'affiche sur le téléphone. Par défaut, aucun arrière-plan ne se trouve derrière la boîte de dialogue. Pour définir un arrière-plan personnalisé, déclarez un thème d'application pour voiture dans votre fichier AndroidManifest.xml et définissez l'attribut carPermissionActivityLayout pour votre thème d'application pour voiture.

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

Définissez ensuite l'attribut carPermissionActivityLayout pour le thème de votre application pour voitures:

<resources>
  <style name="MyCarAppTheme">
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

Démarrer une application pour voiture avec un intent

Vous pouvez appeler la méthode CarContext.startCarApp pour effectuer l'une des actions suivantes:

L'exemple suivant montre comment créer une notification avec une action qui ouvre votre application avec un écran affichant les détails d'une réservation de parking. Vous étendez l'instance de notification avec un intent de contenu contenant un PendingIntent encapsulant un intent explicite pour l'action de votre application:

Kotlin

val notification = notificationBuilder
    ...
    .extend(
        CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(ComponentName(context, MyNotificationReceiver::class.java)),
                    0))
            .build())

Java

Notification notification = notificationBuilder
    ...
    .extend(
        new CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    new Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(new ComponentName(context, MyNotificationReceiver.class)),
                    0))
            .build());

Votre application doit également déclarer un BroadcastReceiver qui est appelé pour traiter l'intent lorsque l'utilisateur sélectionne l'action dans l'interface de notification et appelle CarContext.startCarApp avec un intent incluant l'URI de données:

Kotlin

class MyNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intentAction = intent.action
        if (ACTION_VIEW_PARKING_RESERVATION == intentAction) {
            CarContext.startCarApp(
                intent,
                Intent(Intent.ACTION_VIEW)
                    .setComponent(ComponentName(context, MyCarAppService::class.java))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)))
        }
    }
}

Java

public class MyNotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) {
            CarContext.startCarApp(
                intent,
                new Intent(Intent.ACTION_VIEW)
                    .setComponent(new ComponentName(context, MyCarAppService.class))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)));
        }
    }
}

Enfin, la méthode Session.onNewIntent de votre application gère cet intent en poussant l'écran de réservation de parking sur la pile, s'il n'est pas déjà en haut:

Kotlin

override fun onNewIntent(intent: Intent) {
    val screenManager = carContext.getCarService(ScreenManager::class.java)
    val uri = intent.data
    if (uri != null
        && MY_URI_SCHEME == uri.scheme
        && MY_URI_HOST == uri.schemeSpecificPart
        && ACTION_VIEW_PARKING_RESERVATION == uri.fragment
    ) {
        val top = screenManager.top
        if (top !is ParkingReservationScreen) {
            screenManager.push(ParkingReservationScreen(carContext))
        }
    }
}

Java

@Override
public void onNewIntent(@NonNull Intent intent) {
    ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
    Uri uri = intent.getData();
    if (uri != null
        && MY_URI_SCHEME.equals(uri.getScheme())
        && MY_URI_HOST.equals(uri.getSchemeSpecificPart())
        && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment())
    ) {
        Screen top = screenManager.getTop();
        if (!(top instanceof ParkingReservationScreen)) {
            screenManager.push(new ParkingReservationScreen(getCarContext()));
        }
    }
}

Pour en savoir plus sur la gestion des notifications pour l'application pour voiture, consultez la section Afficher les notifications.

Restrictions concernant les modèles

L'hôte limite le nombre de modèles à afficher pour une tâche donnée à cinq maximum, dont le dernier doit être l'un des types suivants:

Notez que cette limite s'applique au nombre de modèles et non au nombre d'instances Screen dans la pile. Par exemple, si une application envoie deux modèles sur l'écran A, puis pousse l'écran B, elle peut désormais envoyer trois autres modèles. Si chaque écran est structuré pour envoyer un seul modèle, l'application peut également insérer cinq instances d'écran dans la pile ScreenManager.

Ces restrictions comportent des cas particuliers: actualisations de modèle, opérations de retour et de réinitialisation.

Actualisations de modèles

Certaines mises à jour de contenu ne sont pas comptabilisées dans la limite de modèles. En règle générale, si une application envoie un nouveau modèle du même type et contenant le même contenu principal que le modèle précédent, le nouveau modèle n'est pas comptabilisé dans le quota. Par exemple, la mise à jour de l'état d'activation/de désactivation d'une ligne dans un ListTemplate n'est pas comptabilisée dans le quota. Consultez la documentation des différents modèles pour en savoir plus sur les types de mises à jour de contenu pouvant être considérées comme une actualisation.

Opérations de retour

Pour activer les sous-flux dans une tâche, l'hôte détecte quand une application affiche un Screen à partir de la pile ScreenManager et met à jour le quota restant en fonction du nombre de modèles par lesquels l'application recule.

Par exemple, si l'application envoie deux modèles sur l'écran A, puis pousse l'écran B et envoie deux autres modèles, un quota reste disponible. Si l'application revient à l'écran A, l'hôte réinitialise le quota à trois, car l'application est revenue en arrière de deux modèles.

Notez que, lorsqu'elle revient à un écran, une application doit envoyer un modèle du même type que celui envoyé en dernier par cet écran. L'envoi de tout autre type de modèle génère une erreur. Toutefois, tant que le type reste le même lors d'une opération "Retour", une application peut modifier librement le contenu du modèle sans affecter le quota.

Réinitialiser des opérations

Certains modèles comportent une sémantique spéciale qui indique la fin d'une tâche. Par exemple, NavigationTemplate est une vue qui doit rester à l'écran et être actualisée avec de nouvelles instructions détaillées pour l'utilisateur. Lorsqu'il atteint l'un de ces modèles, l'hôte réinitialise le quota de modèles, le traitant comme s'il s'agissait de la première étape d'une nouvelle tâche. Cela permet à l'application de démarrer une nouvelle tâche. Consultez la documentation des différents modèles pour savoir lesquels déclenchent une réinitialisation sur l'hôte.

Si l'hôte reçoit un intent pour démarrer l'application à partir d'une action de notification ou du lanceur d'applications, le quota est également réinitialisé. Ce mécanisme permet à une application de démarrer un nouveau flux de tâches à partir de notifications, et cela est vrai même si une application est déjà liée et au premier plan.

Pour en savoir plus sur l'affichage des notifications de votre application sur l'écran de la voiture, consultez la section Afficher les notifications. Consultez la section Démarrer une application pour voiture avec un intent pour savoir comment démarrer votre application à partir d'une action de notification.

API Connection

Vous pouvez déterminer si votre application s'exécute sur Android Auto ou Android Automotive OS à l'aide de l'API CarConnection pour récupérer des informations de connexion au moment de l'exécution.

Par exemple, dans le Session de votre application pour voitures, initialisez un CarConnection et abonnez-vous aux mises à jour LiveData:

Kotlin

CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)

Java

new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);

Dans l'observateur, vous pouvez ensuite réagir aux modifications de l'état de la connexion:

Kotlin

fun onConnectionStateUpdated(connectionState: Int) {
  val message = when(connectionState) {
    CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit"
    CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS"
    CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto"
    else -> "Unknown car connection type"
  }
  CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show()
}

Java

private void onConnectionStateUpdated(int connectionState) {
  String message;
  switch(connectionState) {
    case CarConnection.CONNECTION_TYPE_NOT_CONNECTED:
      message = "Not connected to a head unit";
      break;
    case CarConnection.CONNECTION_TYPE_NATIVE:
      message = "Connected to Android Automotive OS";
      break;
    case CarConnection.CONNECTION_TYPE_PROJECTION:
      message = "Connected to Android Auto";
      break;
    default:
      message = "Unknown car connection type";
      break;
  }
  CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show();
}

API Constraints

Différents véhicules peuvent permettre d'afficher un nombre différent d'instances Item à l'utilisateur à la fois. Utilisez ConstraintManager pour vérifier la limite de contenu au moment de l'exécution et définir le nombre approprié d'éléments dans vos modèles.

Commencez par obtenir un ConstraintManager à partir du CarContext:

Kotlin

val manager = carContext.getCarService(ConstraintManager::class.java)

Java

ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

Vous pouvez ensuite interroger l'objet ConstraintManager récupéré pour connaître la limite de contenu appropriée. Par exemple, pour obtenir le nombre d'éléments pouvant être affichés dans une grille, appelez getContentLimit avec CONTENT_LIMIT_TYPE_GRID:

Kotlin

val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)

Java

int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);

Ajouter un flux de connexion

Si votre application propose une expérience de connexion aux utilisateurs, vous pouvez utiliser des modèles tels que SignInTemplate et LongMessageTemplate avec le niveau d'API de l'application pour voitures 2 et versions ultérieures pour gérer la connexion à votre application sur l'unité principale de la voiture.

Pour créer un SignInTemplate, définissez un SignInMethod. La bibliothèque d'applications pour voitures est actuellement compatible avec les méthodes de connexion suivantes:

  • InputSignInMethod pour la connexion avec un nom d'utilisateur/un mot de passe.
  • PinSignInMethod pour la connexion par code PIN, où l'utilisateur associe son compte depuis son téléphone à l'aide d'un code affiché sur l'unité principale.
  • ProviderSignInMethod pour la connexion au fournisseur, comme Google Sign-In et One Tap.
  • QRCodeSignInMethod pour la connexion par code QR, où l'utilisateur scanne un code QR pour se connecter sur son téléphone. Cette fonctionnalité est disponible avec le niveau d'API de Car App 4 ou supérieur.

Par exemple, pour implémenter un modèle qui collecte le mot de passe de l'utilisateur, commencez par créer un InputCallback pour traiter et valider la saisie de l'utilisateur:

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
}

Java

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
};

Un InputCallback est requis pour le Builder InputSignInMethod.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

Java

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

Enfin, utilisez votre nouveau InputSignInMethod pour créer un SignInTemplate.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

Java

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

Utiliser AccountManager

Les applications Android Automotive OS avec authentification doivent utiliser AccountManager pour les raisons suivantes :

  • Meilleure expérience utilisateur et gestion de compte simplifiée: les utilisateurs peuvent facilement gérer tous leurs comptes à partir du menu "Comptes" dans les paramètres système, y compris la connexion et la déconnexion.
  • Expériences des invités: les voitures étant des appareils partagés, les OEM peuvent activer l'expérience "Invité" dans le véhicule, lorsque l'ajout de comptes n'est pas permis.

Ajouter des variantes de chaîne de texte

La taille de l'écran de votre voiture peut varier et donc la quantité de texte affichée. Avec l'API Car App de niveau 2 ou supérieur, vous pouvez spécifier plusieurs variantes d'une chaîne de texte pour l'adapter au mieux à l'écran. Pour savoir où les variantes de texte sont acceptées, recherchez les modèles et les composants qui acceptent un CarText.

Vous pouvez ajouter des variantes de chaîne de texte à un CarText à l'aide de la méthode CarText.Builder.addVariant():

Kotlin

val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()

Java

CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

Vous pouvez ensuite utiliser ce CarText, par exemple comme texte principal d'un GridItem.

Kotlin

GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()

Java

new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

Ajoutez les chaînes dans l'ordre de préférence la plus élevée à la moins préférée (par exemple, de la plus longue à la plus courte). L'hôte choisit la chaîne de longueur appropriée en fonction de l'espace disponible sur l'écran de la voiture.

Ajouter des icônes de voiture intégrées pour les lignes

Vous pouvez ajouter des icônes dans le texte pour enrichir l'attrait visuel de votre application à l'aide de CarIconSpan. Pour en savoir plus sur la création de ces plages, consultez la documentation sur CarIconSpan.create. Consultez Appliquer des styles à du texte avec des objets Span pour en savoir plus sur le fonctionnement de l'application de styles à du texte avec des objets Span.

Kotlin

  
val rating = SpannableString("Rating: 4.5 stars")
rating.setSpan(
    CarIconSpan.create(
        // Create a CarIcon with an image of four and a half stars
        CarIcon.Builder(...).build(),
        // Align the CarIcon to the baseline of the text
        CarIconSpan.ALIGN_BASELINE
    ),
    // The start index of the span (index of the character '4')
    8,
    // The end index of the span (index of the last 's' in "stars")
    16,
    Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val row = Row.Builder()
    ...
    .addText(rating)
    .build()
  
  

Java

  
SpannableString rating = new SpannableString("Rating: 4.5 stars");
rating.setSpan(
        CarIconSpan.create(
                // Create a CarIcon with an image of four and a half stars
                new CarIcon.Builder(...).build(),
                // Align the CarIcon to the baseline of the text
                CarIconSpan.ALIGN_BASELINE
        ),
        // The start index of the span (index of the character '4')
        8,
        // The end index of the span (index of the last 's' in "stars")
        16,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
);
Row row = new Row.Builder()
        ...
        .addText(rating)
        .build();
  
  

API de matériel automobile

À partir du niveau d'API 3 de Car App, la bibliothèque d'applications pour voiture contient des API que vous pouvez utiliser pour accéder aux propriétés et aux capteurs du véhicule.

Conditions requises

Pour utiliser les API avec Android Auto, commencez par ajouter une dépendance sur androidx.car.app:app-projected au fichier build.gradle de votre module Android Auto. Pour Android Automotive OS, ajoutez une dépendance à androidx.car.app:app-automotive au fichier build.gradle de votre module Android Automotive OS.

En outre, dans votre fichier AndroidManifest.xml, vous devez déclarer les autorisations appropriées nécessaires pour demander les données de voiture que vous souhaitez utiliser. Notez que l'utilisateur doit également vous accorder ces autorisations. Vous pouvez utiliser le même code sur Android Auto et Android Automotive OS, plutôt que de créer des flux dépendants de la plate-forme. Toutefois, les autorisations requises sont différentes.

CarInfo

Ce tableau décrit les propriétés affichées par les API CarInfo et les autorisations que vous devez demander pour les utiliser:

Méthodes Propriétés Autorisations Android Auto Autorisations Android Automotive OS Prise en charge depuis le niveau d'API de Car App
fetchModel Marque, modèle, année android.car.permission.CAR_INFO 3
fetchEnergyProfile Types de connecteurs pour VE, types de carburants com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

Ces données ne sont disponibles que sur certains véhicules équipés d'Android Automotive OS exécutant l'API 30 ou une version ultérieure.

Dimensions extérieures N/A android.car.permission.CAR_INFO 7
addTollListener
removeTollListener
État de la carte de péage, type de carte de péage 3
addEnergyLevelListener
removeEnergyLevelListener
Niveau de la batterie, niveau de carburant, niveau de carburant faible, autonomie restante com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_ENERGY,
android.car.permission.CAR_ENERGY_PORTS,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addSpeedListener
removeSpeedListener
Vitesse brute, vitesse d'affichage (affichée sur l'écran du cluster de la voiture) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addMileageListener
removeMileageListener
Distance au compteur kilométrique com.google.android.gms.permission.CAR_MILEAGE Ces données ne sont pas disponibles sur Android Automotive OS pour les applications installées depuis le Play Store. 3

Par exemple, pour obtenir la plage restante, instanciez un objet CarInfo, puis créez et enregistrez un OnCarDataAvailableListener:

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

Java

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

Ne partez pas du principe que les données de la voiture sont toujours disponibles. Si une erreur se produit, vérifiez l'état de la valeur que vous avez demandée pour mieux comprendre pourquoi les données que vous avez demandées n'ont pas pu être récupérées. Pour obtenir la définition complète de la classe CarInfo, consultez la documentation de référence.

CarSensors

La classe CarSensors vous permet d'accéder à l'accéléromètre, au gyroscope, à la boussole et aux données de localisation du véhicule. La disponibilité de ces valeurs peut dépendre de l'OEM. Le format des données de l'accéléromètre, du gyroscope et de la boussole est le même que celui que vous obtiendriez avec l'API SensorManager. Par exemple, pour vérifier l'orientation du véhicule:

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

Java

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

Pour accéder aux données de localisation de la voiture, vous devez également déclarer et demander l'autorisation android.permission.ACCESS_FINE_LOCATION.

Tests

Pour simuler des données de capteurs lors des tests sur Android Auto, consultez les sections Capteurs et Configuration des capteurs du guide de l'unité principale pour ordinateur. Pour simuler les données des capteurs lors des tests sur Android Automotive OS, consultez la section Simuler l'état matériel du guide de l'émulateur Android Automotive OS.

Cycle de vie de CarAppService, de la session et de l'écran

Les classes Session et Screen implémentent l'interface LifecycleOwner. Lorsque l'utilisateur interagit avec l'application, les rappels de cycle de vie de vos objets Session et Screen sont appelés, comme décrit dans les diagrammes suivants.

Cycles de vie d'un CarAppService et d'une session

Figure 1. Cycle de vie de Session.

Pour en savoir plus, consultez la documentation de la méthode Session.getLifecycle.

Cycle de vie d'un écran

Figure 2. Cycle de vie de Screen.

Pour en savoir plus, consultez la documentation de la méthode Screen.getLifecycle.

Enregistrer à partir du micro de la voiture

À l'aide de CarAppService et de l'API CarAudioRecord de votre application, vous pouvez lui accorder l'accès au micro de la voiture de l'utilisateur. Les utilisateurs doivent autoriser votre application à accéder au micro de la voiture. Votre application peut enregistrer et traiter les entrées de l'utilisateur dans votre application.

Autorisation d'enregistrement

Avant d'enregistrer des données audio, vous devez d'abord déclarer l'autorisation d'enregistrement dans votre AndroidManifest.xml et demander à l'utilisateur de l'accorder.

<manifest ...>
   ...
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   ...
</manifest>

Vous devez demander l'autorisation d'enregistrer au moment de l'exécution. Pour savoir comment demander une autorisation dans votre application pour voitures, consultez la section Demander des autorisations.

Enregistrer un fichier audio

Une fois que l'utilisateur a autorisé l'enregistrement, vous pouvez enregistrer l'audio et le traiter.

Kotlin

val carAudioRecord = CarAudioRecord.create(carContext)
        carAudioRecord.startRecording()

        val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE)
        while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording()
 

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        carAudioRecord.startRecording();

        byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE];
        while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording();
 

Priorité audio

Lorsque vous enregistrez à partir du micro de la voiture, commencez par acquérir la mise au point audio pour vous assurer que tous les contenus multimédias en cours sont arrêtés. Si vous perdez la sélection audio, arrêtez l'enregistrement.

Voici un exemple de procédure à suivre pour acquérir la priorité audio:

Kotlin

 
val carAudioRecord = CarAudioRecord.create(carContext)
        
        // Take audio focus so that user's media is not recorded
        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
            // Use the most appropriate usage type for your use case
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
            .build()
        
        val audioFocusRequest =
            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                .setAudioAttributes(audioAttributes)
                .setOnAudioFocusChangeListener { state: Int ->
                    if (state == AudioManager.AUDIOFOCUS_LOSS) {
                        // Stop recording if audio focus is lost
                        carAudioRecord.stopRecording()
                    }
                }
                .build()
        
        if (carContext.getSystemService(AudioManager::class.java)
                .requestAudioFocus(audioFocusRequest)
            != AudioManager.AUDIOFOCUS_REQUEST_GRANTED
        ) {
            // Don't record if the focus isn't granted
            return
        }
        
        carAudioRecord.startRecording()
        // Process the audio and abandon the AudioFocusRequest when done

Java

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        // Take audio focus so that user's media is not recorded
        AudioAttributes audioAttributes =
                new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        // Use the most appropriate usage type for your use case
                        .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                        .build();

        AudioFocusRequest audioFocusRequest =
                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                        .setAudioAttributes(audioAttributes)
                        .setOnAudioFocusChangeListener(state -> {
                            if (state == AudioManager.AUDIOFOCUS_LOSS) {
                                // Stop recording if audio focus is lost
                                carAudioRecord.stopRecording();
                            }
                        })
                        .build();

        if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest)
                != AUDIOFOCUS_REQUEST_GRANTED) {
            // Don't record if the focus isn't granted
            return;
        }

        carAudioRecord.startRecording();
        // Process the audio and abandon the AudioFocusRequest when done
 

Bibliothèque de test

La bibliothèque de test Android pour voitures fournit des classes auxiliaires que vous pouvez utiliser pour valider le comportement de votre application dans un environnement de test. Par exemple, SessionController vous permet de simuler une connexion à l'hôte et de vérifier que les Screen et Template appropriés sont créés et renvoyés.

Pour en savoir plus, consultez les exemples.

Signaler un problème lié à la bibliothèque d'applications Android for Cars

Si vous rencontrez un problème avec la bibliothèque, signalez-le à l'aide de l'Issue Tracker de Google. Veillez à fournir toutes les informations requises dans le modèle dédié.

Signaler un nouveau problème

Avant de signaler un nouveau problème, veuillez vérifier s'il figure dans les notes de version de la bibliothèque ou dans la liste des problèmes. Vous pouvez vous abonner et voter pour des problèmes en cliquant sur l'étoile correspondant à un problème dans l'outil de suivi. Pour en savoir plus, consultez S'abonner à un problème.