Détails techniques

Cette section fournit des informations techniques spécifiques à l'application de référence du centre de contrôle.

Le centre de contrôle est une application non groupée, privilégiée et signée par le système qui nécessite une version minimale du SDK de 35 (Android V, niveau d'API 35). L'application est installée dans system/priv-app pour utiliser les System APIs. Pour lire les informations multimédias, l'application doit être signée par la plate-forme. Vous pouvez mettre à jour l'application Over-the-Air (OTA).

Service d'arrière-plan

L'application du centre de contrôle repose sur un service d'arrière-plan pour ses fonctionnalités. Control Center Service est démarré à l'état user-post-unlocked du cycle de vie de l'utilisateur par Vendor ServiceController. Le centre de contrôle doit toujours être actif et communiquer en arrière-plan. L'application ne peut pas dépendre de l'ouverture de l'application par l'utilisateur.

Control Center Service se connecte à d'autres instances de lui-même dans d'autres zones d'occupant et communique avec elles à l'aide de l'API Communication. Il est essentiel de lire le guide d'intégration pour comprendre comment les instances du centre de contrôle de chaque utilisateur établissent des connexions, et envoient et reçoivent des données.

Diagramme illustrant le service Control Center initié par le Vendor ServiceController.
Figure 5. Service du centre de contrôle démarré par le contrôleur de service du fournisseur.

Communication

Une fois connecté, le Control Center Service communique avec des protobuf objets qui transmettent des informations. Pour transmettre le protobuf à une autre zone d'occupant avec les Communication APIs, le protobuf est converti en byte array, un payload object est créé et le Payload est envoyé via CarOccupantConnectionManager#sendPayload.

message ControlCenterPayload {
    required Type messageType = 1;
    // ...
    enum Type {
       MEDIA_STATUS = 0;
       MEDIA_COMMAND = 1;
       INPUT_LOCK_COMMAND = 2;
       INPUT_LOCK_SUCCESSFUL = 3;
       CANCEL_AUDIO_REQUEST = 4;
       MIRRORING_REQUEST_RECEIVER_DECISION = 5;
       MIRRORING_SESSION_ENDED = 6;
    }
}

private fun parsePayload(
    senderZone: OccupantZoneInfo,
    payload: Payload
) {
     val parsedPayload =
         ControlCenterPayload.parseFrom(payload.bytes)
             when (parsedPayload.messageType) {
                 ControlCenterPayload.Type.MEDIA_STATUS -> {
                     // logic here
                 }
             }
             //…
}

Données

Les informations sur les zones d'occupant sont stockées dans le centre de contrôle sous la forme d'objets OccupantZoneData. Les modifications apportées au OccupantZoneData local sont envoyées à d'autres instances du centre de contrôle via l'Comms API.

Lorsque le Payload reçu est analysé, les données analysées sont transmises au OccupantZoneStateRepository local qui, à son tour, notifie les vues de la modification. La plupart des données sont transmises entre les classes avec Kotlin flows on Android.

Gérer les demandes audio des enceintes de l'habitacle

Pour que le conducteur puisse toujours recevoir des demandes de passagers pour diffuser de l'audio sur les enceintes de l'habitacle, lorsqu'il est créé, le Control Center Service enregistre le Primary ZoneMedia Audio RequestCallback.

Le rappel est informé des appels à CarAudioManager#requestMediaAudioOnPrimaryZone. Le Control Center Service du conducteur gère les demandes en créant une notification prioritaire (HUN) qui peut être acceptée ou refusée via CarAudioManager#allowMediaAudioOnPrimaryZone(boolean).

Regarder une vidéo à plusieurs sur différents écrans

Le visionnage à plusieurs fonctionne grâce aux Task Mirroring APIs dans CarActivityManager. Le TaskMirroringManager recherche d'abord le package de l'application MediaSession en cours de lecture dans CarActivityManager#getVisibleTasks, puis crée un VirtualDisplay et déplace la tâche visible vers cet écran via CarActivityManager#moveRootTaskToDisplay.

Cela renvoie un IBinder jeton que MirroredSurfaceView peut utiliser dans une mise en page pour afficher la tâche via MirroredSurfaceView#mirrorSurface. L'objet Communication API Payload a transmis le jeton à d'autres zones d'occupant.

Chaque instance du centre de contrôle dans ces zones d'occupant lance une Mirroring activity et utilise ce jeton pour remplir le MirroredSurfaceView.

Flux d'un jeton de duplication pour afficher une tâche sur un autre écran.
Figure 6. Mise en miroir d'un flux de jetons.

API de mise en miroir des tâches

Le centre de contrôle utilise les API de mise en miroir des tâches suivantes :

CarActivityManager#getVisibleTasks(int displayId)
<ActivityManager.RunningTaskInfo> appelé pour l'écran de l'expéditeur.

CarActivityManager#moveRootTaskToDisplay(int virtualDisplayId)
Déplace la tâche visible sélectionnée vers un écran virtuel créé.

CarActivityManager#createTaskMirroringToken(int taskId)
Crée une tâche pour mettre en miroir le jeton IBinder et doit être appelé une fois la tâche déplacée vers l'écran virtuel.

MirroredSurfaceView#mirrorSurface(IBinder token)
Objet de vue personnalisé qui utilise le jeton pour afficher le contenu de l'écran virtuel.

Limites de la mise en miroir des tâches dans le centre de contrôle

Le centre de contrôle n'est compatible avec la mise en miroir des tâches que pour les applications MediaSession. Toutefois, l'API peut mettre en miroir n'importe quelle tâche. L'écran virtuel est créé avec les dimensions de l'écran de l'expéditeur. Si l'écran du destinataire utilise des résolutions et des dimensions différentes, l'écran virtuel s'affiche au centre de l'écran.

Tâches visibles en surface

Le centre de contrôle étend le châssis Theme.CarUi.NoToolbar pour en faire une fenêtre translucide. Cela signifie que lorsque le centre de contrôle est ouvert sur une tâche, celle-ci est renvoyée dans CarActivityManager#getVisibleTasks, ce qui permet de la mettre en miroir.

Recevoir des informations de mise en miroir

Le centre de contrôle informe les autres applications des sessions de mise en miroir. Pour recevoir des mises à jour, les applications doivent être liées au Control Center Service et envoyer une Handler classe en tant que client, qui reçoit et gère les Messages du Control Center Service.

Les applications clientes peuvent recevoir le nom de package de l'application mise en miroir et lancer un intent URI pour l'activité dans le centre de contrôle hébergeant l'application mise en miroir avec ces clés :

  • _config_msg_mirroring_pkg_name_key_
  • _config_msg_mirroring_redirect_uri_key_

Ces configurations doivent exister dans les ressources de l'application cliente et dans les ressources du centre de contrôle.

Les applications clientes reçoivent des informations de duplication depuis le centre de contrôle.
Figure 7. Recevoir des informations de mise en miroir du centre de contrôle.

Déboguer le centre de contrôle

La classe Logger gère les journaux du centre de contrôle, qui peuvent être configurés pour forcer les journaux.

class Logger(cls: Class<*>) {

   companion object {
       private const val FORCE_LOGS = false
   }

   private val tag: String

   init {
       tag = cls.simpleName
   }

   fun v(message: String) {
       if (Log.isLoggable(tag, Log.VERBOSE) || FORCE_LOGS) {
           Log.v(tag, message)
       }
   }
...

Application système et possibilité de mise à jour

Étant donné que le centre de contrôle est une application système et qu'il est signé par la plate-forme en raison de l'utilisation d' autorisations de signature uniquement, il doit être préinstallé sur l'appareil et ne peut être mis à jour que par OTA, comme l'application Car Media.

Compiler le centre de contrôle à partir de la source

Pour obtenir le code source du centre de contrôle, consultez Intégrer des applications non groupées.

Confidentialité des utilisateurs avec plusieurs écrans

Le centre de contrôle permet à tous les passagers de la voiture de consulter les informations multimédias sur tous les écrans. Google vous recommande d'insérer un avis de confidentialité non bloquant pour informer les utilisateurs. Google vous recommande de le faire au niveau du système, lorsque vous vous connectez à un écran.