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
. À 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
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:
Dans cette illustration, les couleurs indiquent les éléments suivants:
- Jaune
CarService
etCarNavigationStatusManager
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:
CarService
initialiseInstrumentClusterRenderingService
.- Lors de l'initialisation,
InstrumentClusterRenderingService
met à jourCarService
avec :- 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).
- Options d'activité requises pour lancer des activités dans l'écran du groupe d'instruments. Pour en savoir plus, consultez ActivityOptions.
- Une application de navigation (telle que Google Maps pour Android Auto ou toute application de cartes disposant des autorisations requises) :
- Permet d'obtenir un
CarAppFocusManager
à l'aide de la classe Car de car-lib. - Avant le début des instructions détaillées, appelez
CarAppFocusManager.requestFocus()
pour transmettreCarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION
comme paramètreappType
.
- Permet d'obtenir un
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égorieandroid.car.cluster.NAVIGATION
.- Si elle est trouvée, l'application de navigation utilise le
ActivityOptions
signalé par leInstrumentClusterRenderingService
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é parCarService
:<uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
Implémenter InstrumentClusterRenderingService
Pour créer le service:
- É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. - 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).
- Lorsque l'écran indiqué ci-dessus est prêt, ce service doit appeler
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()
pour définir leActivityOptions
exact à utiliser pour afficher une activité sur le tableau de bord. Utilisez les paramètres suivants :category.
ClusterRenderingService.ActivityOptions.
InstanceActivityOptions
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));
- 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.
- 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:
- 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.
- Connectez un écran secondaire physique à l'HU (si compatible) ou activez l'HU secondaire virtuel :
- Sélectionnez Mode développeur dans l'application Paramètres.
- Accédez à Paramètres > Système > Avancé > Options pour les développeurs > Simuler des écrans secondaires.
- Redémarrer l'HU
- Pour lancer l'application KitchenSink:
- Ouvrez le tiroir.
- Accédez à Inst. Cluster (Cluster d'inst.).
- 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.