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.
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.android:singleUser. À tout moment, au maximum une 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 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 (UP) : un appareil Android capable d'exécuter Android 9 (ou version ultérieure). Cet appareil doit disposer de son propre écran et être capable d'afficher les nouvelles versions d'Android.
- Cluster d'instruments est l'une des valeurs suivantes :
- Écran secondaire physique connecté à l'unité principale : si le matériel et le noyau de l'appareil permettent de gérer plusieurs écrans.
- Unité indépendante : Toute unité de calcul connectée à l'UP via une connexion réseau, capable de recevoir et d'afficher un flux vidéo sur son propre écran.
- Écran émulé : pendant le 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 AOSP Android, 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 limite que cet écran est superposé à l'écran principal.
- Tableau de bord émulé : L'émulateur Android inclus dans AAOS permet 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 de ces trois éléments :
CarService- Applications de navigation
- Service de cluster d'instruments OEM

CarService
CarService sert d'intermédiaire entre les applications de navigation et la voiture. Il s'assure qu'une seule application de navigation est active à un moment donné et que seules les applications disposant de l'autorisation android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL peuvent envoyer des données à la voiture.
CarService amorce tous les services spécifiques à la voiture et fournit un accès à ces services par le biais d'une série de gestionnaires. Pour interagir avec les services, les applications exécutées dans la voiture peuvent accéder à ces gestionnaires.
Pour implémenter le bloc d'instruments, les OEM automobiles doivent créer une implémentation personnalisée d'InstrumentClusterRendererService et mettre à jour ClusterRenderingService.
Lors du rendu d'un tableau de bord, pendant le processus de démarrage, CarService lit la clé InstrumentClusterRendererService de ClusterRenderingService pour localiser une implémentation de InstrumentClusterService. Dans AOSP, cette entrée pointe vers le service de rendu de l'implémentation de cluster de l'exemple d'API Navigation State :
<string name="instrumentClusterRendererService"> android.car.cluster/.ClusterRenderingService </string>
Le service mentionné dans 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 lié.
(Dans ce cas, lié fait référence à Services Android.)
Service de cluster d'instruments
Les OEM doivent créer un package Android (APK) contenant une sous-classe de ClusterRenderingService.
Cette classe a deux objectifs :
- Fournit une interface entre Android et le périphérique de rendu du tableau de bord (l'objectif de cette page).
- Reçoit et affiche les mises à jour de l'état de navigation, comme 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 l'habitacle et communiquer ces informations à CarService en appelant les méthodes InstrumentClusterRendererService.setClusterActivityOptions() et InstrumentClusterRendererService.setClusterActivityState().
Pour la deuxième fonction, le service Instrument Cluster 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 les données d'événement encodées dans un bundle.
Séquence d'intégration
Le schéma suivant illustre l'implémentation d'un état de navigation qui affiche les mises à jour :
Dans cette illustration, les couleurs indiquent les éléments suivants :
- Jaune :
CarServiceetCarNavigationStatusManagerfournis par la plate-forme Android. Pour en savoir plus, consultez Voiture et CAR_NAVIGATION_SERVICE. - Cyan
InstrumentClusterRendererServiceimplémenté par l'OEM. - Violet : application de navigation implémentée par Google et des développeurs tiers.
- Green.
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 :
CarServiceinitialiseInstrumentClusterRenderingService.- Lors de l'initialisation,
InstrumentClusterRenderingServicemet à jourCarServiceavec :- Propriétés d'affichage du tableau de bord, telles que les limites non masquées (plus de détails sur les limites non masquées ci-dessous).
- Options d'activité nécessaires pour lancer des activités sur l'écran du groupe d'instruments. Pour en savoir plus, consultez ActivityOptions.
- Une application de navigation (telle que Google Maps pour Android Automotive ou toute application de cartographie disposant des autorisations requises) :
- Obtient un
CarAppFocusManagerà l'aide de la classe Car de car-lib. - Avant le début de la navigation détaillée, appelez
CarAppFocusManager.requestFocus()pour transmettreCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONen tant que paramètreappType.
- Obtient un
CarAppFocusManagercommunique cette requête àCarService. Si elle est accordée,CarServiceinspecte le package d'application de navigation et localise une activité marquée avec la catégorieandroid.car.cluster.NAVIGATION.- Si elle est trouvée, l'application de navigation utilise la
ActivityOptionssignalée par leInstrumentClusterRenderingServicepour lancer l'activité et inclut les propriétés d'affichage du tableau de bord 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 à AndroidManifest.xml. Cela est nécessaire pour s'assurer qu'une seule copie du service Instrument Cluster s'exécute, même pendant l'initialisation et le changement d'utilisateur :
android:singleUser="true" - Détenir l'autorisation système
BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Cela garantit que seul le service de rendu du tableau de bord inclus dans l'image système Android est lié par leCarService:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
Implémenter InstrumentClusterRenderingService
Pour créer le service :
- Écrivez une classe qui s'étend à partir de ClusterRenderingService, puis ajoutez une entrée correspondante à votre fichier
AndroidManifest.xml. Cette classe contrôle l'affichage du groupe d'instruments et peut (facultativement) afficher les données de l'API Navigation State. - Pendant
onCreate(), utilisez ce service pour initialiser la communication avec le matériel de rendu. Les options sont les suivantes :- Déterminez l'écran secondaire à utiliser pour le tableau de bord.
- Créez un écran virtuel pour que l'application Instrument Cluster affiche et transmette l'image rendue à une unité externe (à l'aide d'un format de streaming vidéo, tel que H.264).
- Lorsque l'affichage indiqué ci-dessus est prêt, ce service doit appeler
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()pour définir leActivityOptionsexact qui doit être utilisé pour afficher une activité sur le tableau de bord. Utilisez ces paramètres :category.ClusterRenderingService.ActivityOptions.InstanceActivityOptionspouvant être utilisée pour lancer une activité dans le cluster d'instruments. Par exemple, à partir de l'implémentation du cluster d'instruments dans AOSP :getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- Lorsque le tableau de bord est prêt à afficher les activités, ce service doit appeler
InstrumentClusterRenderingService#setClusterActivityState(). Utilisez ces paramètres :categoryClusterRenderingService.- Bundle
stategénéré avec ClusterRenderingService. Veillez à fournir les données suivantes :visibleSpécifie que le tableau de bord est visible et prêt à afficher du contenu.unobscuredBoundsRectangle qui définit la zone de l'écran du tableau de bord dans laquelle il est possible d'afficher du contenu. Par exemple, les zones couvertes par les cadrans et les jauges.
- Remplacez la méthode
Service#dump()et signalez les 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'UP, s'il est connu pour être 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 nommée getAppTypeOwner(), qui permet au service de cluster écrit par les OEM de savoir quelle application de navigation a le focus de navigation à un moment donné. Les OEM peuvent utiliser la méthode CarAppFocusManager#addFocusListener() existante, puis getAppTypeOwner() pour savoir quelle application est au premier plan. Grâce à ces informations, les OEM peuvent :
- Basculez l'activité affichée dans le cluster vers l'activité du cluster fournie par l'application de navigation sélectionnée.
- Peut détecter si l'application de navigation sélectionnée possède une activité de cluster ou non. Si l'application de navigation sélectionnée ne comporte aucune 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 général, une seule instance de ce type d'application est en cours d'exécution (ou est sélectionnée) dans le système.
Utilisez la méthode CarAppFocusManager#addFocusListener(..) pour écouter les changements de focus 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 sélectionné. 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 } ...
Identifier les applications de modèle
Pour les applications de navigation basées sur des modèles qui utilisent la bibliothèque d'applications automobiles, CarAppFocusManager#getAppTypeOwner() renvoie le nom du package de l'hôte (par exemple, com.google.android.apps.automotive.templates.host), car l'hôte détient le focus système au nom de l'application cliente.
Pour identifier l'application cliente de navigation, les OEM peuvent extraire le nom du package du bundle d'état de navigation envoyé avec CarNavigationStatusManager. Le nom du package est stocké sous la clé active_app_package_name dans le bundle reçu par NavigationRenderer#onNavigationStateChanged(Bundle) :
// In your NavigationRenderer implementation @Override public void onNavigationStateChanged(Bundle bundle) { if (bundle.containsKey("active_app_package_name")) { String activeAppPackage = bundle.getString("active_app_package_name"); // Use the package name to identify the navigating app (e.g., com.waze) } }
Annexe : Utiliser l'application exemple
AOSP fournit une application exemple qui implémente l'API Navigation State.
Pour exécuter cet exemple d'application :
- Créez et installez Android Auto sur une unité principale compatible. Suivez les instructions de compilation et de flashage d'Android spécifiques à votre appareil. Pour obtenir des instructions, consultez Utiliser des tableaux de référence.
- Connectez un écran secondaire physique à l'unité principale (si elle est compatible) ou activez l'unité principale secondaire virtuelle :
- Sélectionnez Mode développeur dans l'application Paramètres.
- Accédez à Paramètres > Système > Avancé > Options pour les développeurs > Simuler les écrans secondaires.
- Redémarrer l'UP
- Pour lancer l'application KitchenSink :
- Ouvrez le tiroir.
- Accédez à Cluster d'instances.
- Cliquez sur DÉMARRER LES MÉTADONNÉES.
KitchenSink demande à ce que la NAVIGATION soit mise au point, ce qui indique au service DirectRenderingCluster d'afficher une interface utilisateur simulée sur le tableau de bord.