API de clúster de instrumentos

Usar la API de Instrument Cluster (una API de Android) para mostrar apps de navegación incluido Google Maps, en una pantalla secundaria de un automóvil, como detrás del el volante en el panel de instrumentos. En esta página, se describe cómo crear un para controlar esa pantalla secundaria e integrar el servicio con CarService para que las apps de navegación puedan mostrar una interfaz de usuario.

Terminología

En esta página, se usan los siguientes términos.

CarInstrumentClusterManager
Una instancia de CarManager que permite que apps externas inicien una actividad en el clúster de instrumentos y recibir devoluciones de llamada cuando esté listo para mostrarse. de datos.
CarManager
La clase base de todos los administradores que usan las apps externas para interactuar con un vehículo específico que implementa CarService.
CarService
Servicio de la plataforma de Android que proporciona comunicación entre apps externas (incluido Google Maps) y funciones específicas de vehículos, como el acceso al clúster de instrumentos.
Destino
El destino final al que navegará el vehículo.
Hora estimada de llegada (ETA)
Es la hora estimada de llegada al lugar de destino.
Unidad principal (HU)
Unidad de procesamiento principal incorporada en un automóvil. El HU ejecuta todo el código de Android que esté conectada a la pantalla central del automóvil.
Clúster de instrumentos
Pantalla secundaria ubicada detrás del volante y entre el vehículo con instrumentos. Puede ser una unidad de procesamiento independiente conectada al HU a través de la red interna del vehículo (CAN bus) o una pantalla secundaria conectado al HU.
InstrumentClusterRenderingService
Clase base para el servicio que se usa para interactuar con el clúster de instrumentos pantalla. Los OEMs deben proporcionar una extensión de esta clase que interactúe con el hardware específico del OEM.
App de KitchenSink
App de prueba incluida con Android Automotive.
Ruta
Es una ruta específica por la que navega un vehículo para llegar a un destino.
Servicio singleton
Un servicio de Android con el atributo android:singleUser. En en un momento dado, como máximo, una instancia del servicio se ejecuta en el sistema Android.

Requisitos previos

Antes de continuar, asegúrate de tener estos elementos:

  • Entorno de desarrollo de Android. Para configurar la app de Android entorno de desarrollo, consulta Requisitos de compilación.
  • Descarga el código fuente de Android. Obtén la última versión de el código fuente de Android de la rama pi-car-release (o una versión posterior) en https://android.googlesource.com
  • Unidad central (HU). Un dispositivo Android capaz de ejecutar Android 9 (o versiones posteriores) Este dispositivo debe tener su propia pantalla y ser capaz de escribir en la pantalla con nuevas compilaciones de Android.
  • El clúster de instrumentos es una de las siguientes opciones:
    • Pantalla física secundaria conectada al HU Si el botón el hardware del dispositivo y el kernel admiten la administración de varias pantallas.
    • Unidad independiente. Cualquier unidad de procesamiento conectada al HU a través de una conexión de red, capaz de recibir y mostrar una transmisión de video por Internet en su propia pantalla.
    • Pantalla emulada. Durante el desarrollo, puedes usar uno de estos entornos emulados:
      • Pantallas secundarias simuladas. Para habilitar una simulación pantalla secundaria en cualquier distribución de AOSP para Android, ve a Opciones para desarrolladores la configuración en la app del sistema Settings y, luego, selecciona inversión secundaria pantallas Esta configuración es equivalente a conectar una secundaria física gráfico principal, con la limitación de que este se superponga pantalla.
      • Clúster de instrumentos emulado: El emulador de Android incluido con AAOS proporciona una opción para mostrar un clúster de instrumentos con ClusterRenderingService.

Arquitectura de la integración

Componentes de integración

Cualquier integración de la API de Instrument Cluster consta de estos tres componentes:

  • CarService
  • Apps de navegación
  • Servicio de clústeres de instrumentos de OEM

Componentes de integración

CarService

CarService media entre las apps de navegación y el automóvil, lo que garantiza que solo una app de navegación está activa en un momento dado y solo las apps con el El permiso android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL puede enviar datos al automóvil.

CarService inicia todos los servicios específicos del vehículo y proporciona acceso a estos servicios a través de una serie de administradores. Para interactuar con los servicios, las apps que se ejecutan en el vehículo pueden acceder a estos administradores.

Para la implementación de clústeres de instrumentos, los OEM de la industria automotriz deben crear un clúster personalizado implementación de InstrumentClusterRendererService y actualiza el ClusterRenderingService.

Cuando se renderiza un clúster de instrumentos, durante el proceso de inicio, el CarService lee la clave InstrumentClusterRendererService de la ClusterRenderingService para ubicar una implementación de InstrumentClusterService. En el AOSP, esta entrada apunta al servicio de renderización de la implementación de clústeres de muestra de la API de Navigation State:

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

El servicio al que se hace referencia en esta entrada se inicializa y se vincula a CarService Cuando las apps de navegación, como Google Maps, solicitan un CarInstrumentClusterManager, CarService proporciona un administrador que actualiza el estado del clúster de instrumentos desde el InstrumentClusterRenderingService vinculado. (En este caso, bound se refiere a En Android Servicios).

Servicio del clúster de instrumentos

Los OEMs deben crear un paquete de Android (APK) que contenga una subclase de ClusterRenderingService.

Esta clase tiene dos propósitos:

  • Proporciona una interfaz para Android y el dispositivo de renderización del clúster de instrumentos (el propósito de esta página).
  • Recibe y renderiza actualizaciones del estado de navegación, como las instrucciones paso a paso la guía de navegación.

En primer lugar, las implementaciones de OEM de InstrumentClusterRendererService debes inicializar la pantalla secundaria que se usa para renderizar la información en las pantallas de la cabina del vehículo y comunicarle esta información a CarService llamando al InstrumentClusterRendererService.setClusterActivityOptions() y InstrumentClusterRendererService.setClusterActivityState().

Para la segunda función, el servicio de clúster de instrumentos debe proporcionar un implementación del ClusterRenderingService que recibe eventos de actualización de estado de navegación, que están codificados como un eventType y datos de eventos codificados en un paquete.

Secuencia de integración

En el siguiente diagrama, se ilustra la implementación de un estado de navegación que procesa actualizaciones:

Secuencia de integración

En esta ilustración, los colores denotan lo siguiente:

  • Amarillo. CarService y CarNavigationStatusManager que proporciona la plataforma de Android. Para obtener más información, consulta Automóvil y CAR_NAVIGATION_SERVICE.
  • Cian. Se implementaron InstrumentClusterRendererService por el OEM.
  • Púrpura. La app de Navigation implementada por Google y terceros desarrolladores.
  • verde. CarAppFocusManager. Para obtener más información, consulta Cómo usar la API de CarAppFocusManager a continuación y CarAppFocusManager.

El flujo de información del estado de navegación sigue esta secuencia:

  1. CarService inicializa InstrumentClusterRenderingService.
  2. Durante la inicialización, InstrumentClusterRenderingService se actualiza CarService con:
    1. Propiedades de pantalla del clúster de instrumentos, como límites claros (obtén más detalles sobre los límites visibles más adelante).
    2. Opciones de actividad necesarias para iniciar actividades dentro de la pantalla del clúster de instrumentos. Para obtener más información, consulta ActivityOptions.
  3. Una app de navegación (como Google Maps para Android Automotive o cualquier app de mapas) con los permisos necesarios):
    1. Obtiene un CarAppFocusManager con la clase Car de car-lib.
    2. Antes de que comiencen las indicaciones paso a paso, llama a CarAppFocusManager.requestFocus() para aprobar CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION como appType parámetro.
  4. CarAppFocusManager comunica esta solicitud a CarService. Si se otorga, CarService inspecciona el paquete de la app de navegación y localiza un actividad marcada con la categoría android.car.cluster.NAVIGATION.
  5. Si lo encuentra, la app de navegación usa el ActivityOptions que informa la InstrumentClusterRenderingService para iniciar la actividad e incluye el elemento Instrumenta las propiedades de visualización del clúster como extras en el intent.

Integra la API

La implementación de InstrumentClusterRenderingService debe hacer lo siguiente:

  • Agregarás el siguiente valor a el archivo AndroidManifest.xml. Esto es necesario para garantizar que una única copia del Se ejecuta el servicio del clúster de instrumentos, incluso durante la inicialización y el cambio de usuario:
    android:singleUser="true"
  • Conserva el permiso del sistema BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE. Esta garantiza que solo el servicio de renderización del clúster de instrumentos se incluya de la imagen del sistema Android se vincula alguna vez a CarService:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

Cómo implementar InstrumentClusterRenderingService

Para compilar el servicio, sigue estos pasos:

  1. Escribe una clase que se extienda de ClusterRenderingService y, luego, agrega la entrada correspondiente a tu archivo AndroidManifest.xml. Esta clase controla la pantalla del clúster de instrumentos y puede (opcional) renderizar el estado de navegación de Google Cloud.
  2. Durante onCreate(), usa este servicio para inicializar la comunicación con el el hardware de procesamiento. Se incluyen las siguientes opciones:
    • Determina la pantalla secundaria que se usará para el clúster de instrumentos.
    • Crea una pantalla virtual para que la app del clúster de instrumentos renderice y transmita el renderizada en una unidad externa (con un formato de transmisión de video por Internet, como H.264)
  3. Cuando la pantalla indicada anteriormente esté lista, este servicio debe llamar InstrumentClusterRenderingService#setClusterActivityLaunchOptions() para definir el ActivityOptions exacto que se debe usar para mostrar una actividad en la Clúster de instrumentos. Usa estos parámetros:
    • category. ClusterRenderingService
    • ActivityOptions.: Es una instancia ActivityOptions que se puede que se usa para iniciar una actividad en el clúster de instrumentos. Por ejemplo, a partir de la muestra Implementación del clúster de instrumentos en AOSP:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
      
  4. Cuando el clúster de instrumentos esté listo para mostrar actividades, este servicio debe invocar InstrumentClusterRenderingService#setClusterActivityState() Usar estas opciones parámetros:
    • category ClusterRenderingService
    • state Paquete generado con ClusterRenderingService Asegúrate de proporcionar estos datos:
      • visible: Especifica el clúster de instrumentos como visible y listo para mostrar contenido.
      • unobscuredBounds Es un rectángulo que define el área dentro del Pantalla del clúster de instrumentos en la que es seguro mostrar contenido. Por ejemplo, las áreas cubiertos por diales y medidores.
  5. Anula el método Service#dump() y proporciona información de estado útil para lo siguiente: depuración (consulta dumpsys para obtener más información).

Ejemplo de implementación de InstrumentClusterRenderingService

En el siguiente ejemplo, se muestra a grandes rasgos un InstrumentClusterRenderingService implementación, que crea un VirtualDisplay para presentar el objeto Instrument. Agrupa contenido en una pantalla física remota.

Como alternativa, este código podría pasar el displayId de una secundaria física conectada al HU, si se sabe que hay uno disponible.

/**
* 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);
  }
}

Usa la API de CarAppFocusManager

La API de CarAppFocusManager proporciona un método llamado getAppTypeOwner(), que permite El servicio de clúster escrito por los OEMs para saber qué app de navegación tiene enfoque de navegación en un determinado tiempo. Los OEM pueden usar el método CarAppFocusManager#addFocusListener() existente. Luego, usa getAppTypeOwner() para conocer qué app se enfoca. Con esta información, Los OEM pueden hacer lo siguiente:

  • Cambia la actividad que se muestra en el clúster a la que proporciona la app de navegación manteniendo el foco.
  • Puede detectar si la app de navegación enfocada tiene o no una actividad de clúster. Si el enfoque no tiene una actividad de clúster (o, si esa actividad está inhabilitada), los OEMs pueden enviar esta señal al DIM del vehículo para que se omita por completo la faceta de navegación del clúster.

Usa CarAppFocusManager para establecer y escuchar el enfoque actual de la app, por ejemplo, la navegación activa o un comando por voz. Por lo general, solo una instancia de esa app está activa que se ejecutan (o enfocados) en el sistema.

Usa el método CarAppFocusManager#addFocusListener(..) para escuchar el enfoque de la app cambios:

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
}

Usa el método CarAppFocusManager#getAppTypeOwner(..) para recuperar el paquete. nombres del propietario actual de un tipo de aplicación determinado que se enfoca. Este método puede mostrar más de un nombre de paquete si el propietario actual utiliza la función 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: Usa la app de ejemplo

AOSP proporciona una app de ejemplo que implementa la API de Navigation State.

Para ejecutar esta app de ejemplo, haz lo siguiente:

  1. Compila y escribe Android Auto en la memoria flash en un HU compatible. Usa el Instrucciones de compilación y escritura en la memoria flash de Android específicas para tu dispositivo Para obtener instrucciones, consulta Cómo usar las placas de referencia.
  2. Conecta una pantalla secundaria física al HU (si es compatible) o activa el modo HU secundario:
    1. Selecciona Modo de desarrollador en la app de Configuración.
    2. Ve a Configuración > Sistema > Avanzado > Opciones para desarrolladores > Simula pantallas secundarias.
  3. Reinicia el HU
  4. Sigue estos pasos para iniciar la app KitchenSink:
    1. Abre el panel lateral.
    2. Vaya a Inst. Clúster.
    3. Haz clic en INICIAR METADATOS.

KitchenSink solicita el foco de NAVIGATION, que le indica a DirectRenderingCluster. para mostrar una interfaz de usuario simulada en el clúster de instrumentos.