绘制地图

使用以下模板的导航、地图注点 (POI) 和天气应用可以通过访问 Surface 来绘制地图。

如需使用以下模板,您的应用必须在 AndroidManifest.xml 文件中的 <uses-permission> 元素中声明以下相应权限之一。

模板 权限 指南
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES 导航
MapWithContentTemplate

androidx.car.app.NAVIGATION_TEMPLATES

androidx.car.app.MAP_TEMPLATES

导航POI天气

MapTemplate

已弃用

androidx.car.app.NAVIGATION_TEMPLATES 导航

PlaceListNavigationTemplate

已弃用

androidx.car.app.NAVIGATION_TEMPLATES 导航

RoutePreviewNavigationTemplate

已弃用

androidx.car.app.NAVIGATION_TEMPLATES 导航

请参阅参考实现

如需查看完整的参考实现,请参阅导航示例

声明界面权限

除了应用所用模板所需的权限之外,应用还必须在其 AndroidManifest.xml 文件中声明 androidx.car.app.ACCESS_SURFACE 权限,才能访问 Surface:

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

访问 Surface

如需访问宿主提供的 Surface,您必须实现 SurfaceCallback 并将该实现提供给 AppManager 汽车服务。当前 Surface 会通过 onSurfaceAvailable()onSurfaceDestroyed() 回调的 SurfaceContainer 参数传递给您的 SurfaceCallback

Kotlin

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

Java

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

使用虚拟显示屏来渲染内容

除了使用 Canvas API 直接渲染到 Surface 中之外,您还可以使用 VirtualDisplayPresentation API 将视图渲染到 Surface 中,如以下示例所示:

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()
  }
}

使用 Compose 渲染到虚拟显示屏

您可以使用 ComposeView 作为 Presentation 的内容视图。由于 ComposeView 是在 activity 外部使用的,因此请确认它或父视图会传播 LifecycleOwnerSavedStateRegistryOwner。为此,请使用 setViewTreeLifecycleOwnersetViewTreeSavedStateRegistryOwner

Session 已实现 LifecycleOwner。为了同时实现这两个角色,您的实现还可以实现 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()
  }

  ...
}

了解可见表面积

主机可以在地图上绘制模板的界面元素。主机调用 SurfaceCallback.onVisibleAreaChanged 方法来告知最有可能不被遮挡且对用户可见的界面区域。

为了最大限度地减少更改次数,主机还会使用根据当前模板将会始终可见的最小矩形来调用 SurfaceCallback.onStableAreaChanged 方法。

例如,如果导航应用使用的是顶部带有操作栏NavigationTemplate,为了在屏幕上腾出更多空间,当用户未与屏幕互动时,操作栏可以隐藏起来。在这种情况下,将使用相同的矩形对 onStableAreaChangedonVisibleAreaChanged 进行回调。

当操作栏处于隐藏状态时,仅使用较大的区域调用 onVisibleAreaChanged。如果用户与屏幕交互,则仅使用第一个矩形调用 onVisibleAreaChanged

支持深色主题

当主机确定条件允许时,应用必须使用适当的深色将地图重新绘制到 Surface 实例上,如 Android 汽车应用质量中所述。

如需绘制深色地图,请使用 CarContext.isDarkMode 方法。当深色主题状态发生变化时,您会收到对 Session.onCarConfigurationChanged 的调用。

在仪表盘显示屏上绘制地图

除了在主显示屏上绘制地图之外,导航应用还可以支持在方向盘后面的仪表盘显示屏上绘制地图。如需了解详情,请参阅绘制到集群显示屏