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 exibição 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 do 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 de carros implementados por 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 Instrument Cluster.
Destino O destino final para o qual o veículo irá navegar.
ETA Hora prevista de chegada ao destino.
Unidade principal (HU) Unidade computacional primária embutida em um carro. A HU executa todo o código Android e está conectada 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 conectado à HU.
InstrumentClusterRenderingService Classe base para o serviço usado para fazer a 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.
App 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 do 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 na ramificação 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 seu próprio display e ser capaz de piscar o display com novas compilações do Android.
  • O conjunto de instrumentos é um dos seguintes:
    • Visor secundário físico conectado à 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 monitor.
    • Exibição emulada. Durante o desenvolvimento, você pode usar um destes ambientes emulados:
      • Displays secundários simulados. 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 anexar um monitor secundário físico, com a limitação de que esse monitor é sobreposto ao monitor principal.
      • Painel de instrumentos emulado. O emulador do Android incluído no Android Automotive fornece 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. implementação de conjunto de instrumentos de referência para se conectar a este 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 os 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 aplicativos rodando no carro podem acessar esses gerenciadores.

Para a implementação do cluster de instrumentos, os OEMs automotivos devem criar uma implementação personalizada de InstrumentClusterRendererService e atualizar se o serviço ClusterRenderingService está 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 conectado ao monitor 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 de estado de navegação:

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

O serviço referido nesta entrada é inicializado e vinculado a CarService . Quando aplicativos de navegação, como o Google Maps, solicitam um CarInstrumentClusterManager , 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 do serviço ClusterRenderingService conectado ao monitor secundário. O serviço ClusterRenderingService está conectado ao monitor secundário. para uma amostra.

Esta classe serve a dois propósitos:

  • Fornece uma interface Android e o dispositivo de renderização 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 a primeira finalidade, 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 do serviço ClusterRenderingService conectado ao monitor secundário. interface que recebe eventos de atualização de status de navegação, que são codificados como um eventType e dados de eventos 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. 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 terceirizados.
  • 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 agrupamento de instrumentos, 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 rotas passo a passo, chame CarAppFocusManager.requestFocus() para passar CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION como o parâmetro appType .
  4. CarAppFocusManager comunica essa 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 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 InstrumentClusterRenderingService deve:

  • Seja designado como um serviço singleton adicionando o seguinte valor 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 troca de usuário:
    android:singleUser="true"
  • Tenha 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 estende do serviço ClusterRenderingService conectada à exibição secundária.
  2. e adicione uma entrada correspondente ao seu arquivo AndroidManifest.xml . Essa classe controla a exibição do Cluster de instrumentos 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 a exibição secundária a ser usada 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).
  4. Quando o display indicado acima estiver pronto, este 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. O serviço ClusterRenderingService está conectado ao monitor secundário.
    • ActivityOptions. Uma instância ActivityOptions que pode ser usada para iniciar uma Activity no Instrument Cluster. Por exemplo, da amostra 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.
    • O pacote state gerado com o serviço ClusterRenderingService está conectado ao monitor secundário.
    • Certifique-se de fornecer os seguintes dados:
      • visible Especifica o Instrument Cluster como visível e pronto para exibir o conteúdo.
      • unobscuredBounds Um retângulo que define a área dentro da exibição do Instrument Cluster na qual é seguro exibir o 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 uma exibição física remota.

Alternativamente, este 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 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 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 o foco de navegação a qualquer momento. Os OEMs podem usar o método 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 de 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 tal atividade estiver desativada), os OEMs podem enviar esse sinal para o carro DIM 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 um comando de voz. Normalmente, apenas uma instância desse aplicativo está sendo executada ativamente (ou focada) no sistema.

Use o método 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 método CarAppFocusManager#getAppTypeOwner(..) para recuperar os nomes de pacote 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 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 amostra que implementa a API de estado de navegação.

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 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 exibições secundárias .
  3. Reinicie a HU. O serviço ClusterRenderingService está conectado ao monitor secundário.
  4. Para iniciar o aplicativo KitchenSink:
    1. Abra a gaveta.
    2. Ir para Inst. Cluster .
    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.