Cómo dibujar mapas

Las apps de navegación, de lugares de interés (POI) y del clima que usan las siguientes plantillas pueden dibujar mapas accediendo a un Surface.

Para usar las siguientes plantillas, tu app debe declarar uno de estos permisos correspondientes en un elemento <uses-permission> en el archivo AndroidManifest.xml.

Plantilla Permiso Orientación
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES Navegación
MapWithContentTemplate

androidx.car.app.NAVIGATION_TEMPLATES

o

androidx.car.app.MAP_TEMPLATES

Navigation, POI, Weather

MapTemplate

(obsoleto)

androidx.car.app.NAVIGATION_TEMPLATES Navegación

PlaceListNavigationTemplate

(obsoleto)

androidx.car.app.NAVIGATION_TEMPLATES Navegación

RoutePreviewNavigationTemplate

(obsoleto)

androidx.car.app.NAVIGATION_TEMPLATES Navegación

Consulta la implementación de referencia

Para ver una implementación de referencia completa, consulta el ejemplo de Navigation.

Declara el permiso de superficie

Además del permiso requerido para la plantilla que usa tu app, esta debe declarar el permiso androidx.car.app.ACCESS_SURFACE en su archivo AndroidManifest.xml para obtener acceso a la plataforma:

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
  ...
</manifest>

Accede a la superficie

Para acceder al Surface que proporciona el host, debes implementar un SurfaceCallback y proporcionar esa implementación al servicio de automóvil AppManager. El Surface actual se pasa a tu SurfaceCallback en el parámetro SurfaceContainer de las devoluciones de llamada onSurfaceAvailable() y onSurfaceDestroyed().

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

Java

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

Cómo usar una pantalla virtual para renderizar contenido

Además de renderizar directamente en el Surface con la API de Canvas, también puedes renderizar Views en el Surface con las APIs de VirtualDisplay y Presentation, como se muestra en este ejemplo:

class HelloWorldSurfaceCallback(context: Context) : SurfaceCallback {
  lateinit var virtualDisplay: VirtualDisplay
  lateinit var presentation: Presentation

  override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
      virtualDisplay = context
          .getSystemService(DisplayManager::class.java)
          .createVirtualDisplay(
              VIRTUAL_DISPLAY_NAME ,
              surfaceContainer.width,
              surfaceContainer.height,
              surfaceContainer.dpi,
              surfaceContainer.surface,
              0
          )

      presentation = Presentation(context, virtualDisplay.display)

      // Instantiate the view to be used as the content view
      val view = ...

      presentation.setContentView(view)
      presentation.show()
  }

  override fun onSurfaceDestroyed(surfaceContainer: SurfaceContainer) {
    presentation.dismiss()
    // This handles releasing the Surface provided when creating the VirtualDisplay
    virtualDisplay.release()
  }
}

Usa Compose para renderizar en la pantalla virtual

Puedes usar un ComposeView como vista de contenido del Presentation. Como ComposeView se usa fuera de una actividad, confirma que este o una vista principal propaguen un LifecycleOwner y un SavedStateRegistryOwner. Para ello, usa setViewTreeLifecycleOwner y setViewTreeSavedStateRegistryOwner.

Session ya implementa LifecycleOwner. Para cumplir con ambos roles, tu implementación también puede implementar SavedStateRegistryOwner.

class HelloWorldSession() : Session(), SavedStateRegistryOwner { ... }

class HelloWorldSurfaceCallback(session: HelloWorldSession) : SurfaceCallback {
  ...

  override fun onSurfaceAvailable(surfaceContainer: SurfaceContainer) {
    ...
    val view = ComposeView(session.carContext)
    view.setViewTreeLifecycleOwner(session)
    view.setViewTreeSavedStateRegistryOwner(session)
    view.setContent {
      // Composable content
    }

    presentation.setContentView(view)
    presentation.show()
  }

  ...
}

Comprende el área visible de la superficie

El host puede dibujar elementos de la interfaz de usuario para las plantillas en la parte superior del mapa. El host llama al método SurfaceCallback.onVisibleAreaChanged para comunicar el área de la superficie que es más probable que no esté obstruida y que sea visible para el usuario.

Para minimizar la cantidad de cambios, el host llama al método SurfaceCallback.onStableAreaChanged con el rectángulo más pequeño, que siempre está visible según la plantilla actual.

Por ejemplo, cuando una app de navegación usa la NavigationTemplate con una barra de acción en la parte superior, para dejar más espacio en la pantalla, la barra de acción se puede ocultar cuando el usuario no interactúa con la pantalla. En este caso, se genera una devolución de llamada a onStableAreaChanged y onVisibleAreaChanged con el mismo rectángulo.

Cuando la barra de acciones está oculta, solo se llama a onVisibleAreaChanged con el área más grande. Si el usuario interactúa con la pantalla, solo se llamará a onVisibleAreaChanged con el primer rectángulo.

Admite el tema oscuro

Las apps deben volver a dibujar su mapa en la instancia de Surface con los colores oscuros apropiados cuando el host determine que las condiciones lo requieren, como se describe en Calidad de las apps para Android para vehículos.

Para dibujar un mapa oscuro, usa el método CarContext.isDarkMode. Cuando cambia el estado del tema oscuro, recibes una llamada a Session.onCarConfigurationChanged.

Cómo dibujar mapas en la pantalla del clúster

Además de dibujar mapas en la pantalla principal, las apps de navegación también pueden dibujar mapas en la pantalla del clúster detrás del volante. Para obtener más información, consulta Cómo dibujar en la pantalla del clúster.