使用以下模板的导航、地图注点 (POI) 和天气应用可以通过访问 Surface 来绘制地图。
如需使用以下模板,您的应用必须在 AndroidManifest.xml 文件中的 <uses-permission> 元素中声明以下相应权限之一。
| 模板 | 权限 | 指南 |
|---|---|---|
NavigationTemplate |
androidx.car.app.NAVIGATION_TEMPLATES |
导航 |
MapWithContentTemplate |
或
|
导航、 POI、 天气 |
|
(已弃用) |
androidx.car.app.NAVIGATION_TEMPLATES |
导航 |
|
(已弃用) |
androidx.car.app.NAVIGATION_TEMPLATES |
导航 |
(已弃用) |
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 中之外,您还可以使用 VirtualDisplay 和 Presentation 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 外部使用的,因此请确认它或父视图会传播 LifecycleOwner 和 SavedStateRegistryOwner。为此,请使用 setViewTreeLifecycleOwner 和 setViewTreeSavedStateRegistryOwner。
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,为了在屏幕上腾出更多空间,当用户未与屏幕互动时,操作栏可以隐藏起来。在这种情况下,将使用相同的矩形对 onStableAreaChanged 和 onVisibleAreaChanged 进行回调。
当操作栏处于隐藏状态时,仅使用较大的区域调用 onVisibleAreaChanged。如果用户与屏幕交互,则仅使用第一个矩形调用 onVisibleAreaChanged。
支持深色主题
当主机确定条件允许时,应用必须使用适当的深色将地图重新绘制到 Surface 实例上,如 Android 汽车应用质量中所述。
如需绘制深色地图,请使用 CarContext.isDarkMode 方法。当深色主题状态发生变化时,您会收到对 Session.onCarConfigurationChanged 的调用。
在仪表盘显示屏上绘制地图
除了在主显示屏上绘制地图之外,导航应用还可以支持在方向盘后面的仪表盘显示屏上绘制地图。如需了解详情,请参阅绘制到集群显示屏。