Conjunto de instrumentos

Use a API do Instrument Cluster (uma API do Android) para exibir aplicativos de navegação, incluindo o Google Maps, em uma tela secundária em um carro, como atrás do volante no painel de instrumentos. Esta página descreve como criar um serviço para controlar esse monitor secundário e integrá-lo ao CarService para que os aplicativos de navegação possam exibir uma interface de usuário.

Terminologia

Os seguintes termos são usados ​​nesta página:

Prazo Descrição
CarInstrumentClusterManager Um CarManager que permite que aplicativos externos iniciem uma atividade no Instrument Cluster e recebam retornos de chamada quando o Instrument Cluster estiver pronto para exibir atividades.
Car Manager Classe base de todos os gerenciadores usados ​​por aplicativos externos para interagir com serviços específicos do carro implementados pelo CarService .
CarService Serviço da plataforma Android que fornece comunicação entre aplicativos externos (incluindo Google Maps) e recursos específicos do carro, como acesso ao painel de instrumentos.
Destino O destino final para o qual o veículo irá navegar.
ETA Tempo estimado de chegada ao destino.
Unidade principal (HU) Unidade computacional primária embutida em um carro. O HU roda todo o código Android e está conectado ao display central do carro.
Conjunto de instrumentos Visor secundário localizado atrás do volante e entre os instrumentos do carro. Esta pode ser uma unidade computacional independente conectada à HU através da rede interna do carro (barramento CAN) ou um display secundário conectado à HU.
InstrumentClusterRenderingService Classe base para o serviço usado para fazer interface com o display do Instrument Cluster. Os OEMs devem fornecer uma extensão dessa classe que interaja com o hardware específico do OEM.
Aplicativo KitchenSink Aplicativo de teste incluído no Android Automotive.
Rota Um caminho específico ao longo do qual um veículo navega para chegar a um destino.
Serviço singleton Um serviço Android com o atributo android:singleUser . A qualquer momento, no máximo uma instância do serviço é executada no sistema Android.

Pré-requisitos

Para desenvolver a integração, certifique-se de ter estes elementos:

  • Ambiente de desenvolvimento Android. Para configurar o ambiente de desenvolvimento Android, consulte Requisitos de compilação .
  • Baixe o código-fonte do Android. Obtenha a versão mais recente do código-fonte do Android no branch pi-car-release (ou posterior) em https://android.googlesource.com .
  • Unidade Principal (HU). Um dispositivo Android capaz de executar o Android 9 (ou posterior). Este dispositivo deve ter sua própria tela e ser capaz de exibir a tela com novas versões do Android.
  • O cluster de instrumentos é um dos seguintes:
    • Exibição secundária física conectada ao HU. Se o hardware e o kernel do dispositivo suportarem o gerenciamento de vários monitores.
    • Unidade independente. Qualquer unidade computacional conectada à HU por meio de uma conexão de rede, capaz de receber e exibir um fluxo de vídeo em seu próprio display.
    • Exibição emulada. Durante o desenvolvimento, você pode usar um destes ambientes emulados:
      • Exibições secundárias simuladas. Para habilitar uma exibição secundária simulada em qualquer distribuição Android AOSP, vá para as configurações de Opções do desenvolvedor no aplicativo do sistema Configurações e selecione Simular exibições secundárias. Essa configuração é equivalente a conectar um monitor secundário físico, com a limitação de que esse monitor é sobreposto ao monitor primário.
      • Grupo de instrumentos emulado. O emulador do Android incluído no Android Automotive oferece uma opção para exibir um cluster de instrumentos com o emulador do Android _qemu-pipes . Use a implementação do cluster de instrumentos de referência DirectRenderingCluster para se conectar a esse monitor externo emulado.

Arquitetura de integração

Componentes de integração

Qualquer integração da API do Instrument Cluster consiste nestes três componentes:

  • CarService
  • Aplicativos de navegação
  • Serviço de cluster de instrumentos OEM

Componentes de integração

Serviço automotivo

CarService faz a mediação entre os aplicativos de navegação e o carro, garantindo que apenas um aplicativo de navegação esteja ativo a qualquer momento e apenas aplicativos com a permissão android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL podem enviar dados para o carro.

O CarService inicia todos os serviços específicos do carro e fornece acesso a esses serviços por meio de uma série de gerentes. Para interagir com os serviços, os aplicativos executados no carro podem acessar esses gerenciadores.

Para implementação de cluster de instrumentos, os OEMs automotivos devem criar uma implementação personalizada de InstrumentClusterRendererService e atualizar o arquivo config.xml para apontar para essa implementação personalizada.

Ao renderizar um Instrument Cluster, durante o processo de inicialização o CarService lê a chave InstrumentClusterRendererService do config.xml para localizar uma implementação de InstrumentClusterService . No AOSP, esta entrada aponta para o serviço de renderização de implementação de cluster de amostra da API Navigation State:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

O serviço referido nesta entrada é inicializado e vinculado ao CarService . Quando os aplicativos de navegação, como o Google Maps, solicitam um CarInstrumentClusterManager , o CarService fornece um gerenciador que atualiza o estado do Instrument Cluster a partir do InstrumentClusterRenderingService vinculado. (Neste caso, vinculado refere-se a Android Services .)

Serviço de cluster de instrumentos

Os OEMs devem criar um Android Package (APK) que contenha uma subclasse de InstrumentClusterRendererService . Consulte ClusterRenderingService para obter uma amostra.

Esta classe serve a dois propósitos:

  • Fornece uma interface Android e o dispositivo de renderização do Instrument Cluster (o objetivo desta página).
  • Recebe e processa atualizações de estado de navegação, como orientação de navegação passo a passo.

Para o primeiro propósito, as implementações OEM de InstrumentClusterRendererService devem inicializar a exibição secundária usada para renderizar informações nas telas na cabine do carro e comunicar essas informações ao CarService chamando os métodos InstrumentClusterRendererService.setClusterActivityOptions() e InstrumentClusterRendererService.setClusterActivityState() .

Para a segunda função, o serviço Instrument Cluster deve fornecer uma implementação da interface NavigationRenderer que recebe eventos de atualização de status de navegação , que são codificados como um eventType e dados de evento codificados em um pacote.

Sequência de integração

O diagrama a seguir ilustra a implementação de um estado de navegação que renderiza atualizações:

Sequência de integração

Nesta ilustração, as cores denotam o seguinte:

  • Amarelo. CarService e CarNavigationStatusManager fornecidos pela plataforma Android.
  • Ciano. InstrumentClusterRendererService implementado pelo OEM.
  • Roxo. O aplicativo de navegação implementado pelo Google e desenvolvedores de terceiros.
  • Verde. CarAppFocusManager .

O fluxo de informações do Estado de Navegação segue esta sequência:

  1. CarService inicializa o InstrumentClusterRenderingService .
  2. Durante a inicialização, o InstrumentClusterRenderingService atualiza o CarService com:
    1. Propriedades de exibição do Instrument Cluster, como limites não obscuros (consulte mais detalhes sobre limites não obscuros posteriormente).
    2. Opções de atividade necessárias para iniciar atividades dentro da tela do Instrument Cluster (veja mais detalhes em ActivityOptions .
  3. Um aplicativo de navegação (como o Google Maps para Android Automotive ou qualquer aplicativo de mapas com as permissões necessárias):
    1. Obtém um CarAppFocusManager usando a classe Car de car-lib.
    2. Antes do início das direções passo a passo, chama CarAppFocusManager.requestFocus() para passar CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION como o parâmetro appType .
  4. CarAppFocusManager comunica essa solicitação ao CarService . Se concedido, o CarService inspeciona o pacote do aplicativo de navegação e localiza uma atividade marcada com a categoria android.car.cluster.NAVIGATION .
  5. Se encontrado, o aplicativo de navegação usa as ActivityOptions relatadas pelo InstrumentClusterRenderingService para iniciar a atividade e inclui as propriedades de exibição do Instrument Cluster como extras na intenção.

Integrando a API

A implementação do InstrumentClusterRenderingService deve:

  • Seja designado como um serviço singleton adicionando o valor a seguir ao AndroidManifest.xml. Isso é necessário para garantir que uma única cópia do serviço Instrument Cluster seja executada, mesmo durante a inicialização e a troca de usuário:
    android:singleUser="true"
  • Mantenha a permissão do sistema BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE . Isso garante que apenas o serviço de renderização do Instrument Cluster incluído como parte da imagem do sistema Android seja vinculado ao CarService :
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Implementando InstrumentClusterRenderingService

Para construir o serviço:

  1. Escreva uma classe que se estenda de InstrumentClusterRenderingService e adicione uma entrada correspondente ao seu arquivo AndroidManifest.xml . Essa classe controla a exibição do Instrument Cluster e pode ( opcionalmente ) renderizar os dados da API do Estado de Navegação.
  2. Durante onCreate() , use este serviço para inicializar a comunicação com o hardware de renderização. As opções incluem:
    • Determine o display secundário a ser usado para o Instrument Cluster.
    • Crie um display virtual para que o aplicativo Instrument Cluster renderize e transmita a imagem renderizada para uma unidade externa (usando um formato de streaming de vídeo, como H.264).
  3. Quando a exibição indicada acima estiver pronta, esse serviço deve chamar InstrumentClusterRenderingService#setClusterActivityLaunchOptions() para definir as ActivityOptions exatas que devem ser usadas para exibir uma Activity no Instrument Cluster. Use estes parâmetros:
    • categoria. CarInstrumentClusterManager#CATEGORY_NAVIGATION
    • ActivityOptions. Uma instância ActivityOptions que pode ser usada para iniciar uma Activity no Instrument Cluster. Por exemplo, do exemplo de implementação do Instrument Cluster no AOSP:
      getService().setClusterActivityLaunchOptions(
         CATEGORY_NAVIGATION,
         ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
      
  4. Quando o Instrument Cluster estiver pronto para exibir atividades, esse serviço deverá invocar InstrumentClusterRenderingService#setClusterActivityState() . Use estes parâmetros:
    • category CarInstrumentClusterManager#CATEGORY_NAVIGATION
    • state Bundle gerado com ClusterActivityState . Certifique-se de fornecer os seguintes dados:
      • visible Especifica o Instrument Cluster como visível e pronto para exibir conteúdo.
      • unobscuredBounds Um retângulo que define a área dentro da tela do Instrument Cluster na qual é seguro exibir conteúdo. Por exemplo, áreas cobertas por mostradores e medidores.
  5. Substitua o método Service#dump() e relate informações de status úteis para depuração (consulte dumpsys para obter mais informações).

Exemplo de implementação de InstrumentClusterRenderingService

O exemplo a seguir descreve uma implementação de InstrumentClusterRenderingService , que cria um VirtualDisplay para apresentar o conteúdo do Instrument Cluster em um monitor físico remoto.

Alternativamente, este código pode passar o displayId de um display secundário físico conectado ao HU, se houver um disponível.

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display that will 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);
  }
}

Usando CarAppFocusManager

A API CarAppFocusManager fornece um método chamado getAppTypeOwner() , que permite que o serviço de cluster escrito por OEMs saiba qual aplicativo de navegação tem foco de navegação em um determinado momento. Os OEMs podem usar o CarAppFocusManager#addFocusListener() existente e, em seguida, usar getAppTypeOwner() para saber qual aplicativo tem o foco. Com essas informações, os OEMs podem:

  • Alterne a atividade mostrada no cluster para a atividade do cluster fornecida pelo aplicativo de navegação que mantém o foco.
  • Pode detectar se o aplicativo de navegação focado tem uma atividade de cluster ou não. Se o aplicativo de navegação focado não tiver uma atividade de cluster (ou se essa atividade estiver desabilitada), os OEMs poderão enviar esse sinal para o DIM do carro para que a faceta de navegação do cluster seja totalmente ignorada.

Use CarAppFocusManager para definir e ouvir o foco do aplicativo atual, como navegação ativa ou comando de voz. Normalmente, apenas uma instância desse aplicativo está sendo executada ativamente (ou focada) no sistema.

Use o CarAppFocusManager#addFocusListener(..) para ouvir as alterações de foco do aplicativo:

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
}

Use o CarAppFocusManager#getAppTypeOwner(..) para recuperar os nomes de pacote do proprietário atual de um determinado tipo de aplicativo que está em foco. Esse método pode retornar mais de um nome de pacote se o proprietário atual usar o recurso 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 application 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
}

...

Apêndice: Usando o aplicativo de amostra

O AOSP fornece um aplicativo de exemplo que implementa a API Navigation State.

Para executar este aplicativo de exemplo:

  1. Crie e atualize o Android Auto em uma HU compatível. Use as instruções de construção e flash do Android específicas para seu dispositivo. Para obter instruções, consulte Uso de placas de referência .
  2. Conecte um monitor secundário físico à HU (se compatível) ou ligue a HU secundária virtual:
    1. Selecione o modo de desenvolvedor no aplicativo Configurações.
    2. Vá para Configurações > Sistema > Avançado > Opções do desenvolvedor > Simular telas secundárias .
  3. Reinicie o HU. O serviço ClusterRenderingService está conectado à exibição secundária.
  4. Para iniciar o aplicativo KitchenSink:
    1. Abra a gaveta.
    2. Vá para Inst. Agrupar .
    3. Clique em INICIAR METADADOS .

O KitchenSink solicita o foco NAVIGATION, que instrui o serviço DirectRenderingCluster a exibir uma interface de usuário simulada no Instrument Cluster.