Detalhes técnicos

Esta seção fornece detalhes técnicos específicos do app de referência da Central de controle.

A Central de controle é um app de sistema desvinculado e privilegiado que exige uma versão mínima do SDK 35 (Android V, nível 35 da API). O app é instalado em system/priv-app para usar System APIs. Para ler informações de mídia, o app precisa ser assinado pela plataforma. Você pode atualizar o app Over-the-Air (OTA).

Serviço em segundo plano

O app da Central de controle depende de um serviço em segundo plano para funcionar. O Control Center Service é iniciado no estado user-post-unlocked no ciclo de vida do usuário pelo Vendor ServiceController. A Central de controle precisa estar sempre ativa e se comunicando em segundo plano. O app não pode depender de que o usuário o abra.

Control Center Service se conecta e se comunica com outras instâncias de si mesmo em outras zonas de ocupantes usando a API Communication. Ler o guia de integração é essencial para entender como as instâncias da Central de controle em cada usuário estabelecem conexões e enviam e recebem dados.

Diagrama ilustrando o serviço do Control Center sendo iniciado pelo Vendor ServiceController.
Figura 5. Serviço da Central de controle iniciado pelo Vendor ServiceController.

Comunicação

Depois de conectado, o Control Center Service se comunica com protobuf objetos que transmitem informações. Para transmitir o protobuf para outra zona de ocupantes com as Communication APIs, o protobuf é convertido em uma byte array, um payload object é criado e o Payload é enviado por 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
                 }
             }
             //…
}

Dados

As informações sobre as zonas de ocupantes são armazenadas na Central de controle na forma de objetos OccupantZoneData. As mudanças no OccupantZoneData local são enviadas para outras instâncias da Central de controle pela Comms API.

Quando o Payload recebido é analisado, os dados analisados são transmitidos para o OccupantZoneStateRepository local, que, por sua vez, notifica as visualizações da mudança. A maioria dos dados é transmitida entre classes com Kotlin flows on Android.

Processar solicitações de áudio do alto-falante da cabine

Para que o motorista sempre receba solicitações de passageiros para reproduzir áudio nos alto-falantes da cabine, quando criado, o Control Center Service registra o Primary ZoneMedia Audio RequestCallback.

O callback é notificado de chamadas para CarAudioManager#requestMediaAudioOnPrimaryZone. O Control Center Service do motorista processa as solicitações criando uma notificação de alerta (HUN) que pode ser aceita ou recusada por CarAudioManager#allowMediaAudioOnPrimaryZone(boolean).

Assistir a um vídeo em conjunto com outras telas

A assistência conjunta funciona devido às Task Mirroring APIs em CarActivityManager. O TaskMirroringManager pesquisa primeiro o pacote do app MediaSession em reprodução em CarActivityManager#getVisibleTasks e, em seguida, cria um VirtualDisplay e move a tarefa visível para esta tela usando CarActivityManager#moveRootTaskToDisplay.

Isso retorna um token IBinder que MirroredSurfaceView pode usar em um layout para mostrar a tarefa usando MirroredSurfaceView#mirrorSurface. O objeto Communication API Payload transmitiu o token para outras zonas de ocupantes.

Cada instância da Central de controle nessas zonas de ocupantes inicia uma Mirroring activity e usa esse token para preencher a MirroredSurfaceView.

Fluxo de um token de espelhamento para mostrar uma tarefa em outra tela.
Figura 6. Espelhar um fluxo de token.

APIs de espelhamento de tarefas

A Central de controle usa estas APIs de espelhamento de tarefas:

CarActivityManager#getVisibleTasks(int displayId)
<ActivityManager.RunningTaskInfo> chamado para a tela do remetente.

CarActivityManager#moveRootTaskToDisplay(int virtualDisplayId)
Move a tarefa visível selecionada para uma tela virtual criada.

CarActivityManager#createTaskMirroringToken(int taskId)
Cria uma tarefa para espelhar o token IBinder e precisa ser chamada depois que a tarefa é movida para a tela virtual.

MirroredSurfaceView#mirrorSurface(IBinder token)
Um objeto de visualização personalizado que usa o token para mostrar o conteúdo da tela virtual.

Limitações do espelhamento de tarefas na Central de controle

A Central de controle só oferece suporte ao espelhamento de tarefas para apps MediaSession. No entanto, a API pode espelhar qualquer tarefa. A tela virtual é feita com as dimensões da tela do remetente. Se a tela do receptor usar resoluções e dimensões diferentes, a tela virtual vai aparecer no centro da tela.

Tarefas visíveis da superfície

A Central de controle estende o chassi Theme.CarUi.NoToolbar para ser uma janela translúcida. Isso significa que, quando a Central de controle é aberta em uma tarefa, ela é retornada em CarActivityManager#getVisibleTasks, o que permite que a tarefa seja espelhada.

Receber informações de espelhamento

A Central de controle notifica outros apps sobre sessões de espelhamento. Para receber atualizações, os apps precisam se vincular ao Control Center Service e enviar uma Handler classe como um cliente que recebe e processa Messages do Control Center Service.

Os apps clientes podem receber o nome do pacote do app espelhado e iniciar um intent URI para a atividade na Central de controle que hospeda o app espelhado com estas chaves:

  • _config_msg_mirroring_pkg_name_key_
  • _config_msg_mirroring_redirect_uri_key_

Essas configurações precisam existir nos recursos do app cliente e nos recursos da Central de controle.

Os apps clientes recebem informações de espelhamento da Central de controle.
Figura 7. Receber informações de espelhamento da Central de controle.

Depurar a Central de controle

A classe Logger processa os registros da Central de controle, que podem ser configurados para forçar 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 do sistema e capacidade de atualização

Como a Central de controle é um app do sistema e assinado pela plataforma devido ao uso de permissões somente de assinatura, ela precisa ser pré-instalada no dispositivo e só pode ser atualizada por OTA, de maneira semelhante ao app de mídia do carro.

Criar a Central de controle da origem

Para acessar o código-fonte da Central de controle, consulte Integrar apps desvinculados.

Privacidade do usuário com várias telas

A Central de controle permite que todos os passageiros do carro visualizem informações de mídia em todas as telas. O Google recomenda inserir um aviso de privacidade não bloqueador para notificar os usuários. O Google recomenda fazer isso no nível do sistema, quando você fizer login em uma tela.