API Instrument Cluster

Utilisez l'API Instrument Cluster (une API Android) pour afficher des applications de navigation, y compris Google Maps, sur un écran secondaire dans une voiture, par exemple derrière le volant sur le tableau de bord. Cette page explique comment créer un service pour contrôler cet écran secondaire et l'intégrer à CarService afin que les applications de navigation puissent afficher une interface utilisateur.

Terminologie

Les termes suivants sont utilisés sur cette page.

CarInstrumentClusterManager
Instance de CarManager qui permet aux applications externes de lancer une activité sur le groupe d'instruments et de recevoir des rappels lorsque le groupe d'instruments est prêt à afficher des activités.
CarManager
Classe de base de tous les gestionnaires utilisés par les applications externes pour interagir avec les services spécifiques à la voiture implémentés par CarService.
CarService
Service de plate-forme Android qui assure la communication entre les applications externes (y compris Google Maps) et les fonctionnalités spécifiques à la voiture, telles que l'accès au tableau de bord.
Destination
Destination finale vers laquelle le véhicule se dirigera.
Heure d'arrivée prévue (ETA)
Heure d'arrivée estimée à une destination.
Unité principale (HU)
Unité de calcul principale intégrée à une voiture. L'HU exécute tout le code Android et est connecté à l'écran central de la voiture.
Cluster d'instruments
Écran secondaire situé derrière le volant et entre les instruments de la voiture. Il peut s'agir d'une unité de calcul indépendante connectée à l'HU via le réseau interne de la voiture (bus CAN) ou d'un écran secondaire associé à l'HU.
InstrumentClusterRenderingService
Classe de base du service utilisé pour l'interface avec l'écran du combiné d'instruments. Les OEM doivent fournir une extension de cette classe qui interagit avec le matériel spécifique à l'OEM.
Application KitchenSink
Application de test incluse avec Android Automotive.
Itinéraire
Chemin spécifique emprunté par un véhicule pour arriver à destination.
Service Singleton
Service Android avec l'attribut android:singleUser. À un moment donné, une seule instance du service s'exécute sur le système Android.

Prérequis

Avant de continuer, assurez-vous de disposer des éléments suivants:

  • Environnement de développement Android Pour configurer l'environnement de développement Android, consultez la section Exigences de compilation.
  • Téléchargez le code source Android. Obtenez la dernière version du code source Android à partir de la branche pi-car-release (ou version ultérieure) sur https://android.googlesource.com.
  • Unité principale (HU) Un appareil Android capable d'exécuter Android 9 (ou version ultérieure) Cet appareil doit disposer de son propre écran et être capable de flasher l'écran avec de nouvelles versions d'Android.
  • Le cluster d'instruments est l'un des éléments suivants :
    • Écran secondaire physique connecté à l'HU. Si le matériel et le noyau de l'appareil sont compatibles avec la gestion de plusieurs écrans.
    • Unité indépendante. Toute unité de calcul connectée à la passerelle multimédia via une connexion réseau, capable de recevoir et d'afficher un flux vidéo sur son propre écran.
    • Écran émulé Lors du développement, vous pouvez utiliser l'un des environnements émulés suivants :
      • Écrans secondaires simulés. Pour activer un écran secondaire simulé sur n'importe quelle distribution Android AOSP, accédez aux paramètres Options pour les développeurs dans l'application système Paramètres, puis sélectionnez Simuler des écrans secondaires. Cette configuration équivaut à connecter un écran secondaire physique, avec la limitation que cet écran est superposé à l'écran principal.
      • Cluster d'instruments émulé. L'émulateur Android inclus avec AAOS offre une option permettant d'afficher un tableau de bord avec ClusterRenderingService.

Architecture d'intégration

Composants d'intégration

Toute intégration de l'API Instrument Cluster se compose des trois composants suivants:

  • CarService
  • Applications de navigation
  • Service de cluster d'instruments OEM

Composants d'intégration

CarService

CarService sert d'intermédiaire entre les applications de navigation et la voiture, en veillant à ce qu'une seule application de navigation soit active à un moment donné et que seules les applications disposant de l'autorisation android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL puissent envoyer des données à la voiture.

CarService démarre tous les services spécifiques à la voiture et fournit un accès à ces services via une série de gestionnaires. Pour interagir avec les services, les applications exécutées dans la voiture peuvent accéder à ces gestionnaires.

Pour l'implémentation du combiné d'instruments, les OEM automobiles doivent créer une implémentation personnalisée d'InstrumentClusterRendererService et mettre à jour ClusterRenderingService.

Lors du rendu d'un cluster d'instruments, au cours du processus de démarrage, CarService lit la clé InstrumentClusterRendererService du ClusterRenderingService pour localiser une implémentation de InstrumentClusterService. Dans AOSP, cette entrée pointe vers le service de rendu de l'implémentation du cluster de l'exemple d'API Navigation State:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

Le service auquel fait référence cette entrée est initialisé et lié à CarService. Lorsque des applications de navigation, comme Google Maps, demandent un CarInstrumentClusterManager, CarService fournit un gestionnaire qui met à jour l'état du groupe d'instruments à partir du InstrumentClusterRenderingService associé. (Dans ce cas, lié fait référence aux services Android.)

Service du cluster d'instruments

Les OEM doivent créer un package Android (APK) contenant une sous-classe de ClusterRenderingService.

Cette classe a deux fonctionnalités:

  • Fournit une interface Android et le périphérique de rendu du combiné d'instruments (objectif de cette page).
  • Réçoit et affiche les mises à jour de l'état de navigation, telles que les instructions de navigation détaillées.

Pour le premier objectif, les implémentations OEM de InstrumentClusterRendererService doivent initialiser l'écran secondaire utilisé pour afficher des informations sur les écrans de la cabine de la voiture et communiquer ces informations à CarService en appelant les méthodes InstrumentClusterRendererService.setClusterActivityOptions() et InstrumentClusterRendererService.setClusterActivityState().

Pour la deuxième fonction, le service du combiné d'instruments doit fournir une implémentation de l'interface ClusterRenderingService qui reçoit les événements de mise à jour de l'état de navigation, qui sont encodés en tant que eventType et des données d'événement encodées dans un bundle.

Séquence d'intégration

Le diagramme suivant illustre l'implémentation d'un état de navigation qui affiche les mises à jour:

Séquence d&#39;intégration

Dans cette illustration, les couleurs indiquent les éléments suivants:

  • Jaune CarService et CarNavigationStatusManager fournis par la plate-forme Android. Pour en savoir plus, consultez les sections Voiture et CAR_NAVIGATION_SERVICE.
  • Cyan InstrumentClusterRendererService implémenté par l'OEM.
  • Violet. L'application Navigation implémentée par Google et des développeurs tiers
  • Vert. CarAppFocusManager. Pour en savoir plus, consultez Utiliser l'API CarAppFocusManager ci-dessous et CarAppFocusManager.

Le flux d'informations sur l'état de navigation suit cette séquence:

  1. CarService initialise InstrumentClusterRenderingService.
  2. Lors de l'initialisation, InstrumentClusterRenderingService met à jour CarService avec :
    1. Propriétés d'affichage du tableau de bord, telles que les limites non masquées (voir plus d'informations sur les limites non masquées plus loin).
    2. Options d'activité requises pour lancer des activités dans l'écran du groupe d'instruments. Pour en savoir plus, consultez ActivityOptions.
  3. Une application de navigation (telle que Google Maps pour Android Auto ou toute application de cartes disposant des autorisations requises) :
    1. Permet d'obtenir un CarAppFocusManager à l'aide de la classe Car de car-lib.
    2. Avant le début des instructions détaillées, appelez CarAppFocusManager.requestFocus() pour transmettre CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION comme paramètre appType.
  4. CarAppFocusManager transmet cette requête à CarService. Si l'autorisation est accordée, CarService inspecte le package de l'application de navigation et recherche une activité marquée de la catégorie android.car.cluster.NAVIGATION.
  5. Si elle est trouvée, l'application de navigation utilise le ActivityOptions signalé par le InstrumentClusterRenderingService pour lancer l'activité et inclut les propriétés d'affichage du cluster d'instruments en tant qu'extras dans l'intent.

Intégrer l'API

L'implémentation de InstrumentClusterRenderingService doit:

  • Être désigné comme service singleton en ajoutant la valeur suivante au fichier AndroidManifest.xml. Cela permet de s'assurer qu'une seule copie du service du cluster d'instruments s'exécute, même lors de l'initialisation et du changement d'utilisateur:
    android:singleUser="true"
  • Détenez l'autorisation système BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Cela garantit que seul le service de rendu du combiné d'instruments inclus dans l'image système Android est lié par CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Implémenter InstrumentClusterRenderingService

Pour créer le service:

  1. Écrivez une classe qui étend ClusterRenderingService, puis ajoutez une entrée correspondante à votre fichier AndroidManifest.xml. Cette classe contrôle l'écran du groupe d'instruments et peut (facultatif) afficher les données de l'API Navigation State.
  2. Lors de onCreate(), utilisez ce service pour initialiser la communication avec le matériel de rendu. Voici quelques exemples :
    • Déterminez l'écran secondaire à utiliser pour le combiné d'instruments.
    • Créez un écran virtuel pour que l'application du combiné d'instruments effectue le rendu et transmette l'image affichée à une unité externe (à l'aide d'un format de streaming vidéo, tel que H.264).
  3. Lorsque l'écran indiqué ci-dessus est prêt, ce service doit appeler InstrumentClusterRenderingService#setClusterActivityLaunchOptions() pour définir le ActivityOptions exact à utiliser pour afficher une activité sur le tableau de bord. Utilisez les paramètres suivants :
    • category. ClusterRenderingService.
    • ActivityOptions. Instance ActivityOptions pouvant être utilisée pour lancer une activité dans le groupe d'instruments. Par exemple, à partir de l'implémentation de l'exemple de cluster d'instruments sur AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Lorsque le combiné d'instruments est prêt à afficher des activités, ce service doit appeler InstrumentClusterRenderingService#setClusterActivityState(). Utilisez les paramètres suivants :
    • category ClusterRenderingService.
    • Bundle state généré avec ClusterRenderingService. Veillez à fournir les données suivantes :
      • visible Indique que le combiné d'instruments est visible et prêt à afficher du contenu.
      • unobscuredBounds Rectangle qui définit la zone de l'écran du combiné d'instruments dans laquelle il est possible d'afficher du contenu. Par exemple, les zones couvertes par les cadrans et les jauges.
  5. Forcez la méthode Service#dump() et signalez des informations d'état utiles pour le débogage (pour en savoir plus, consultez dumpsys).

Exemple d'implémentation de InstrumentClusterRenderingService

L'exemple suivant décrit une implémentation InstrumentClusterRenderingService, qui crée un VirtualDisplay pour présenter le contenu du cluster d'instruments sur un écran physique distant.

Ce code peut également transmettre le displayId d'un écran secondaire physique connecté à l'HU, si un tel écran est connu comme étant disponible.

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display to be used for instrument
   // cluster
   private final String mUniqueId = UUID.randomUUID().toString();
   // Format of the instrument cluster display
   private static final int DISPLAY_WIDTH = 1280;
   private static final int DISPLAY_HEIGHT = 720;
   private static final int DISPLAY_DPI = 320;
   // Area not covered by instruments
   private static final int DISPLAY_UNOBSCURED_LEFT = 40;
   private static final int DISPLAY_UNOBSCURED_TOP = 0;
   private static final int DISPLAY_UNOBSCURED_RIGHT = 1200;
   private static final int DISPLAY_UNOBSCURED_BOTTOM = 680;
   @Override
   public void onCreate() {
      super.onCreate();
      // Create a virtual display to render instrument cluster activities on
      mDisplayManager = getSystemService(DisplayManager.class);
      VirtualDisplay display = mDisplayManager.createVirtualDisplay(
          mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null,
          0 /* flags */, null, null);
      // Do any additional initialization (e.g.: start a video stream
      // based on this virtual display to present activities on a remote
      // display).
      onDisplayReady(display.getDisplay());
}
private void onDisplayReady(Display display) {
    // Report activity options that should be used to launch activities on
    // the instrument cluster.
    String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION;
    ActionOptions options = ActivityOptions.makeBasic()
        .setLaunchDisplayId(display.getDisplayId());
    setClusterActivityOptions(category, options);
    // Report instrument cluster state.
    Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT,
        DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT,
        DISPLAY_UNOBSCURED_BOTTOM);
    boolean visible = true;
    ClusterActivityState state = ClusterActivityState.create(visible,
       unobscuredBounds);
    setClusterActivityState(category, options);
  }
}

Utiliser l'API CarAppFocusManager

L'API CarAppFocusManager fournit une méthode appelée getAppTypeOwner(), qui permet au service de cluster écrit par les OEM de savoir quelle application de navigation est sélectionnée à un moment donné. Les OEM peuvent utiliser la méthode CarAppFocusManager#addFocusListener() existante, puis getAppTypeOwner() pour savoir quelle application est active. Grâce à ces informations, les OEM peuvent:

  • Remplacez l'activité affichée dans le cluster par l'activité de cluster fournie par l'application de navigation qui détient la sélection.
  • Peut détecter si l'application de navigation active dispose d'une activité de cluster ou non. Si l'application de navigation sélectionnée n'a pas d'activité de cluster (ou si cette activité est désactivée), les OEM peuvent envoyer ce signal au DIM de la voiture afin que la facette de navigation du cluster soit complètement ignorée.

Utilisez CarAppFocusManager pour définir et écouter le focus de l'application actuelle, comme la navigation active ou une commande vocale. En règle générale, une seule instance d'une telle application est en cours d'exécution (ou mise au point) dans le système.

Utilisez la méthode CarAppFocusManager#addFocusListener(..) pour écouter les modifications de la sélection de l'application:

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

...

public void onAppFocusChanged(int appType, boolean active) {
    // Use the CarAppFocusManager#getAppTypeOwner(appType) method call
    // to retrieve a list of active package names
}

Utilisez la méthode CarAppFocusManager#getAppTypeOwner(..) pour récupérer les noms de package du propriétaire actuel d'un type d'application donné qui est au premier plan. Cette méthode peut renvoyer plusieurs noms de package si le propriétaire actuel utilise la fonctionnalité android:sharedUserId.

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner(
              CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) {
        // No Navigation app has focus
        // OEM may choose to show their default cluster view
} else {
       // focusOwnerPackageNames
       // Use the PackageManager to retrieve the cluster activity for the package(s)
       // returned in focusOwnerPackageNames
}

...

Annexe: Utiliser l'application exemple

AOSP fournit un exemple d'application qui implémente l'API Navigation State.

Pour exécuter cet exemple d'application:

  1. Créez et flashez Android Auto sur une unité principale compatible. Utilisez les instructions de compilation et de flash Android spécifiques à votre appareil. Pour obtenir des instructions, consultez la section Utiliser des cartes de référence.
  2. Connectez un écran secondaire physique à l'HU (si compatible) ou activez l'HU secondaire virtuel :
    1. Sélectionnez Mode développeur dans l'application Paramètres.
    2. Accédez à Paramètres > Système > Avancé > Options pour les développeurs > Simuler des écrans secondaires.
  3. Redémarrer l'HU
  4. Pour lancer l'application KitchenSink:
    1. Ouvrez le tiroir.
    2. Accédez à Inst. Cluster (Cluster d'inst.).
    3. Cliquez sur DÉMARRER LES MÉTADONNÉES.

KitchenSink demande la sélection de NAVIGATION, ce qui indique au service DirectRenderingCluster d'afficher une interface utilisateur simulée sur le combiné d'instruments.