Detalles técnicos

En esta sección, se proporcionan detalles técnicos específicos de la app de referencia de Control Center.

El Centro de control es una app privilegiada, no agrupada y firmada por el sistema que requiere una versión mínima del SDK de 35 (Android V, nivel de API 35). La app se instaló en system/priv-app para usar System APIs. Para leer la información de contenido multimedia, la app debe estar firmada por la plataforma. Puedes actualizar la app de forma inalámbrica (OTA).

Servicio en segundo plano

La app de Centro de control depende de un servicio en segundo plano para su funcionalidad. Control Center Service se inicia en el estado user-post-unlocked del ciclo de vida del usuario con Vendor ServiceController. El Centro de control siempre debe estar activo y comunicarse en segundo plano. La app no puede depender de que el usuario la abra.

Control Center Service se conecta con otras instancias de sí mismo en otras zonas de ocupantes y se comunica con ellas a través de la API de Communication. Es fundamental leer la guía de integración para comprender cómo las instancias del Centro de control en cada usuario establecen conexiones y envían y reciben datos.

Diagrama que ilustra el inicio del servicio de Control Center por parte de Vendor ServiceController.
Figura 5: Se inició el servicio de Control Center con Vendor ServiceController.

Comunicación

Una vez que se conecta, el objeto Control Center Service se comunica con los objetos protobuf que transmiten información. Para pasar el protobuf a otra zona de ocupante con el Communication APIs, el protobuf se convierte en un byte array, se crea un payload object y el Payload se envía a través de 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
                 }
             }
             //…
}

Datos

La información sobre las zonas de ocupantes se almacena en el Centro de control en forma de objetos OccupantZoneData. Los cambios en el OccupantZoneData local se envían a otras instancias del Centro de control a través de Comms API.

Cuando se analiza el Payload recibido, los datos analizados se pasan al OccupantZoneStateRepository local que, a su vez, notifica a las vistas sobre el cambio. La mayoría de los datos se pasan entre clases con Kotlin flows on Android.

Cómo controlar las solicitudes de audio de la bocina de cabina

Para que el conductor siempre pueda recibir solicitudes de los pasajeros para reproducir audio en las bocinas de la cabina, cuando se crea, el Control Center Service del conductor registra el Primary ZoneMedia Audio RequestCallback.

Se notifica a la devolución de llamada sobre las llamadas a CarAudioManager#requestMediaAudioOnPrimaryZone. El Control Center Service del conductor controla las solicitudes creando una notificación emergente (HUN) que se puede aceptar o rechazar a través de CarAudioManager#allowMediaAudioOnPrimaryZone(boolean).

Cómo mirar un video en compañía con otras pantallas

La función de Mirar juntos funciona gracias a Task Mirroring APIs en CarActivityManager. TaskMirroringManager primero busca el paquete de la app de MediaSession en CarActivityManager#getVisibleTasks y, luego, crea un VirtualDisplay y mueve la tarea visible a esta pantalla a través de CarActivityManager#moveRootTaskToDisplay.

Esto devuelve un token IBinder que MirroredSurfaceView puede usar en un diseño para mostrar la tarea a través de MirroredSurfaceView#mirrorSurface. El objeto Communication API Payload pasó el token a otras zonas de ocupantes.

Cada instancia de Control Center en esas zonas de ocupantes inicia un Mirroring activity y usa ese token para completar el MirroredSurfaceView.

Flujo de un token de duplicación para mostrar una tarea en otra pantalla.
Figura 6: Duplica un flujo de tokens.

APIs de duplicación de tareas

El Centro de control usa las siguientes APIs de duplicación de tareas:

CarActivityManager#getVisibleTasks(int displayId)
<ActivityManager.RunningTaskInfo> se llama para la pantalla del remitente.

CarActivityManager#moveRootTaskToDisplay(int virtualDisplayId)
Mueve la tarea visible seleccionada a una pantalla virtual creada.

CarActivityManager#createTaskMirroringToken(int taskId)
Crea una tarea para duplicar el token IBinder y se debe llamar después de que la tarea se mueva a la pantalla virtual.

MirroredSurfaceView#mirrorSurface(IBinder token)
Objeto de vista personalizado que usa el token para mostrar el contenido de la pantalla virtual.

Limitaciones de la duplicación de tareas en el Centro de control

El Centro de control solo admite la duplicación de tareas para las apps de MediaSession. Sin embargo, la API puede replicar cualquier tarea. La pantalla virtual se crea con las dimensiones de la pantalla del remitente. Si la pantalla del receptor usa diferentes resoluciones y dimensiones, la pantalla virtual aparecerá en el centro de la pantalla.

Tareas visibles en la superficie

El Centro de control extiende el chasis Theme.CarUi.NoToolbar para que sea una ventana translúcida. Esto significa que, cuando se abre el Centro de control sobre una tarea, esta se devuelve en CarActivityManager#getVisibleTasks, lo que permite duplicarla.

Recibe información de duplicación

El Centro de control notifica a otras apps sobre las sesiones de duplicación. Para recibir actualizaciones, las apps deben vincularse a Control Center Service y enviar una clase Handler como cliente, que recibe y controla Messages desde Control Center Service.

Las apps cliente pueden recibir el nombre del paquete de la app duplicada y lanzar un intent URI para la actividad en el Centro de control que aloja la app duplicada con estas claves:

  • _config_msg_mirroring_pkg_name_key_
  • _config_msg_mirroring_redirect_uri_key_

Estas configuraciones deben existir en los recursos de la app cliente y en los recursos del Centro de control.

Las apps cliente reciben información de duplicación del Centro de control.
Figura 7: Recibe información de duplicación del Centro de control.

Centro de controles de depuración

La clase Logger controla los registros del Centro de control, que se pueden configurar para forzar los registros.

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)
       }
   }
...

App del sistema y capacidad de actualización

Dado que el Centro de control es una app del sistema y está firmada por la plataforma debido al uso de permisos solo de firma, debe estar preinstalado en el dispositivo y solo se puede actualizar de forma inalámbrica, de manera similar a la app de música para automóviles.

Compila el Centro de control desde el código fuente

Para obtener el código fuente del Centro de control, consulta Cómo integrar apps no agrupadas.

Privacidad del usuario con varias pantallas

El Centro de Control permite que todos los pasajeros del automóvil vean la información multimedia en todas las pantallas. Google recomienda que insertes un aviso de privacidad que no bloquee el contenido para notificar a los usuarios. Google recomienda que lo hagas a nivel del sistema, cuando accedas a una pantalla.