API de cluster de instrumentos

Use a API Instrument Cluster (uma API 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 essa exibição secundária e, em seguida, integrar o serviço 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 Uma instância 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.
CarManager Classe base de todos os gerenciadores usados ​​por apps externos para interagir com serviços específicos de carros 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 navegará.
HEC Hora estimada de chegada ao destino.
Unidade principal (HU) Unidade computacional primária embutida em um carro. O HU executa todo o código Android e está conectado ao display central do carro.
Conjunto de instrumentos Display secundário localizado atrás do volante e entre os instrumentos do carro. Pode ser uma unidade computacional independente conectada à HU através da rede interna do carro (barramento CAN) ou um display secundário acoplado à 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 desta 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 único 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 atualizar a tela com novas versões do Android.
  • O conjunto de instrumentos é um dos seguintes:
    • Display secundário físico conectado à HU. Se o hardware e o kernel do dispositivo suportam 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 AOSP Android, vá para as configurações de Opções do desenvolvedor no aplicativo do sistema Configurações e selecione Simular exibições secundárias. Esta configuração equivale a anexar um monitor secundário físico, com a limitação de que esse monitor seja sobreposto ao monitor primário.
      • Conjunto de instrumentos emulado. O emulador Android incluído no Android Automotive oferece uma opção para exibir um painel de instrumentos com o serviço ClusterRenderingService conectado ao monitor secundário.
      • emulador _qemu-pipes. O serviço ClusterRenderingService está conectado ao monitor secundário. referência à implementação do painel de instrumentos para conectar a este display 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 conjunto 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 em um determinado momento e que apenas aplicativos com a permissão android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL possam enviar dados para o carro.

CarService inicializa todos os serviços específicos do carro e fornece acesso a esses serviços por meio de uma série de gerenciadores. Para interagir com os serviços, os apps rodando 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 serviço ClusterRenderingService conectado ao monitor secundário.

Ao renderizar um Instrument Cluster, durante o processo de inicialização, o CarService lê a chave InstrumentClusterRendererService do serviço ClusterRenderingService e está conectado ao display secundário. 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 do estado de navegação:

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

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

Serviço de cluster de instrumentos

Os OEMs devem criar um pacote Android (APK) que contém uma subclasse do serviço ClusterRenderingService conectado ao monitor secundário. O serviço ClusterRenderingService está conectado ao monitor secundário. para uma amostra.

Esta classe tem dois propósitos:

  • Fornece uma interface Android e o dispositivo de renderização Instrument Cluster (objetivo desta página).
  • Recebe e renderiza 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 o display secundário usado para renderizar informações nas telas da 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 do serviço ClusterRenderingService conectado ao display secundário. interface 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 indicam o seguinte:

  • Amarelo. CarService e CarNavigationStatusManager fornecidos pela plataforma Android. Para saber mais, consulte Carro e CAR_NAVIGATION_SERVICE .
  • Ciano. InstrumentClusterRendererService implementado pelo OEM.
  • Roxo. O aplicativo de navegação implementado pelo Google e por desenvolvedores terceiros.
  • Verde. CarAppFocusManager . Para saber mais, consulte Usando a API CarAppFocusManager abaixo e 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 CarService com:
    1. Propriedades de exibição do painel de instrumentos, como limites não obscuros (veja mais detalhes sobre limites não obscuros posteriormente).
    2. Opções de atividades 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 instruções passo a passo, chamadas para CarAppFocusManager.requestFocus() para passar CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION como o parâmetro appType .
  4. CarAppFocusManager comunica esta solicitação ao CarService . Se concedido, 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 ActivityOptions relatado pelo InstrumentClusterRenderingService para iniciar a atividade e inclui as propriedades de exibição do Instrument Cluster como extras na intenção.

Integrar a API

A implementação do InstrumentClusterRenderingService deve:

  • Seja designado como um serviço singleton adicionando o seguinte valor ao AndroidManifest.xml. Isto é necessário para garantir que uma única cópia do serviço Instrument Cluster seja executada, mesmo durante a inicialização e 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"/>
    

Implementar InstrumentClusterRenderingService

Para construir o serviço:

  1. Escreva uma classe que se estende do serviço ClusterRenderingService e está conectada ao monitor secundário.
  2. e adicione uma entrada correspondente ao seu arquivo AndroidManifest.xml . Esta classe controla a exibição do Instrument Cluster e pode ( opcionalmente ) renderizar dados da API do estado de navegação.
  3. 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 painel de instrumentos.
    • 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).
  4. Quando a exibição indicada acima estiver pronta, este serviço deverá chamar InstrumentClusterRenderingService#setClusterActivityLaunchOptions() para definir as ActivityOptions exatas que devem ser usadas para exibir uma atividade no Instrument Cluster. Use estes parâmetros:
    • categoria. O serviço ClusterRenderingService está conectado ao monitor secundário.
    • ActivityOptions. Uma instância ActivityOptions que pode ser usada para iniciar uma atividade no cluster de instrumentos. Por exemplo, do exemplo de implementação do Instrument Cluster no AOSP:
      getService().setClusterActivityLaunchOptions(
         CATEGORY_NAVIGATION,
         ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
      
  5. Quando o Instrument Cluster estiver pronto para exibir atividades, esse serviço deverá invocar InstrumentClusterRenderingService#setClusterActivityState() . Use estes parâmetros:
    • O serviço ClusterRenderingService category está conectado ao monitor secundário.
    • state O pacote gerado com o serviço ClusterRenderingService é conectado ao monitor secundário.
    • Certifique-se de fornecer os seguintes dados:
      • visible Especifica o conjunto de instrumentos 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.
  6. 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 display físico remoto.

Alternativamente, esse código pode passar o displayId de um display secundário físico conectado à HU, se houver algum 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 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);
  }
}

Use a API 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 método CarAppFocusManager#addFocusListener() existente e, em seguida, usar getAppTypeOwner() para saber qual aplicativo está em foco. Com essas informações, os OEMs podem:

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

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

Use o método CarAppFocusManager#addFocusListener(..) para escutar 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 método CarAppFocusManager#getAppTypeOwner(..) para recuperar os nomes dos pacotes do proprietário atual de um determinado tipo de aplicativo que está em foco. Este 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 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
}

...

Apêndice: Use o aplicativo de exemplo

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 atualização do Android específicas para o seu dispositivo. Para obter instruções, consulte Usando 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 Modo de desenvolvedor no aplicativo Configurações.
    2. Vá para Configurações > Sistema > Avançado > Opções do desenvolvedor > Simular monitores secundários .
  3. Reinicie o HU. O serviço ClusterRenderingService está conectado ao monitor secundário.
  4. Para iniciar o aplicativo KitchenSink:
    1. Abra a gaveta.
    2. Vá para Inst. Conjunto .
    3. Clique em INICIAR METADADOS .

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