向停车状态下使用的应用添加 Android Automotive OS 支持

将应用分发到 Android Automotive OS 设备时,您应注意一些特定于设备规格的事项。本指南介绍了这些注意事项。

在 Android Automotive OS 模拟器上测试现有应用

如需开始构建 Android Automotive OS 应用,请先在 Android Automotive OS 模拟器上测试您的现有应用。如需设置模拟器,请按照使用 Android Automotive OS 模拟器进行测试中的步骤操作。然后,您可以按照在模拟器上运行应用中的说明运行该应用。

运行应用时,请注意兼容性问题,例如:

  • 信息娱乐屏幕采用固定屏幕方向。为了符合汽车应用质量指南,应用必须同时支持竖屏和横屏方向。
  • 适用于其他设备的 API 可能不适用于 Android Automotive OS。例如,某些 Google Play 服务 API 不适用于 Android Automotive OS。如需详细了解如何处理这些问题,请参阅停用功能部分。

配置应用的清单文件

如需以 Android Automotive OS 设备为目标平台,应用必须具有特定的清单条目。在您选择加入向 Android Automotive OS 设备分发应用的计划后,Google Play 会审核兼容的应用,以确保其可以在汽车上安全地使用。如需了解详情,请参阅分发至汽车。

必需的 Android Automotive OS 功能

所有专为 Android Automotive OS 构建的应用都必须满足特定要求,才能通过 Google Play 分发。如需了解详情,请参阅满足 Google Play 功能要求。

特定于类别的清单条目

除了上述适用于所有停车时使用的应用的要求之外,视频和游戏类别还有其他要求:

满足驾驶员分心要求

在将应用引入汽车时,避免驾驶员分心至关重要。对于停车状态下使用的应用,这主要是通过在用户体验 (UX) 限制处于启用状态时阻止应用使用或播放音频来实现的,如 DD-2 和 DD-3 质量指南中所述。

在用户体验限制处于已启用状态时阻止使用

默认情况下,当用户体验限制处于有效状态时,无法使用或启动 activity。为确保此行为适用于您的应用,清单中的任何 <activity> 元素都不得包含以下 <meta-data> 元素:

<!-- NOT ALLOWED -->
<meta-data
  android:name="distractionOptimized"
  android:value="true"/>

如果用户体验限制生效时,应用中的 activity 处于已恢复状态,则该 activity 会被操作系统拥有的 activity 遮挡。

至少,应用的 activity 会转换为“已暂停”生命周期状态。此操作会作为 onPause 生命周期回调发生,在此期间,您必须暂停播放应用中的视频和音频。

在包含 Android Automotive OS 兼容模式的设备上,系统屏蔽会导致应用的 activity 从已暂停状态转换为已停止状态。

停止播放并防止恢复播放

对于某些应用,在 onPause() 期间暂停播放并跟踪状态以防止在 onResume() 之前恢复播放,就足以满足驾驶员分心要求。

如果对生命周期回调做出响应对您的应用来说还不够,您可以直接监听用户体验限制状态,如以下部分所述。例如,支持画中画的应用可能更愿意直接监听,而不是在生命周期回调中进行条件检查。

监听用户体验限制

如需监听用户体验限制,请先在应用模块的 build.gradle 文件中添加对 android.car 库的依赖项。这是 Android SDK 的扩展,可提供特定于 Android Automotive OS 的 API。

android {
    ...
    useLibrary("android.car")
}

使用 CarUxRestrictionsManager 读取用户体验限制状态。请勿尝试根据其他硬件状态(例如档位或速度)确定用户体验限制状态,因为用户体验限制可能因车辆内的显示屏而异。

val car = Car.createCar(context) ?: return
val carUxRestrictionsManager =
    car.getCarManager(Car.CAR_UX_RESTRICTION_SERVICE) as? CarUxRestrictionsManager ?: return

// You can either read the state directly ...
val currentUxRestrictions = carUxRestrictionsManager.currentCarUxRestrictions

// or listen to state changes
carUxRestrictionsManager.registerListener { carUxRestrictions: CarUxRestrictions ->
    // Handle UX restrictions
}

// Don't forget to teardown and release resources when they're no longer needed
carUxRestrictionsManager.unregisterListener()
car.disconnect()

您的应用引用的 CarUxRestrictions 提供的唯一值是 isRequiresDistractionOptimization 的返回值。其他值仅与标记为经过防分心优化的 activity 相关。

测试实现效果

使用以下过程验证您的应用是否符合驾驶员分心要求:

  1. 在不含 Google Play 商店或兼容模式的系统映像上安装您的应用。
  2. 在启动器应用网格打开的情况下,模拟驾驶并验证您的应用无法打开。
  3. 停止模拟驾驶,打开应用并进入播放界面,然后开始播放。
  4. 再次模拟驾驶,并验证播放是否暂停。
    1. 如果您的应用支持与 MediaSession 集成,请使用 adb shell cmd media_session dispatch play 并验证播放不会恢复。

针对 Android Automotive OS 优化应用

为了尽可能向用户提供最佳车载体验,请在构建 Android Automotive OS 应用时牢记以下几点:

使用窗口边衬区和刘海屏

与其他设备规格一样,Android Automotive OS 包含系统界面元素(例如状态栏和导航栏),并支持非矩形显示屏。

默认情况下,应用会在不与系统栏或刘海屏重叠的区域中绘制。不过,您可能希望应用隐藏系统栏、在系统栏后面绘制内容,或在刘海屏中显示内容,如在窗口边衬区内布置应用中所述。如果您的应用执行上述任何操作,请参阅以下小节,详细了解如何让您的应用在 Android Automotive OS 设备生态系统中正常运行。

系统栏、沉浸模式和边到边渲染

汽车中的系统栏的大小和位置可能与其他外形规格不同。例如,导航栏可以放置在屏幕的左侧、右侧或底部。即使顶部有状态栏,底部有导航栏(大多数手机和平板电脑都是如此),这些元素在汽车中的尺寸也可能会大得多。

此外,Android Automotive OS 还允许 OEM 控制应用是否可以显示或隐藏系统栏,以进入和退出沉浸模式。例如,通过阻止应用隐藏系统栏,OEM 可以确保车辆控件(例如空调控件)在屏幕上始终可用。如果 OEM 已阻止应用控制系统栏,则当应用调用 WindowInsetsController(或 WindowInsetsControllerCompat)API 来显示或隐藏系统栏时,不会发生任何变化。如需详细了解如何检测应用是否能够修改边衬区,请参阅 show 和 hide 的文档。

同样,OEM 也可以控制应用是否可以设置系统栏的颜色和半透明度,以确保系统栏及其包含的元素始终清晰可见。如果您的应用采用全屏绘制,请检查是否只有非关键内容绘制在系统栏后面。 如果设备 OEM 阻止设置系统栏的颜色或半透明度,则此内容可能不可见。

<!-- Depending on OEM configuration, these style declarations
     (and the corresponding runtime calls) may be ignored -->
<style name="...">
  <item name="android:statusBarColor">...</item>
  <item name="android:navigationBarColor">...</item>
  <item name="android:windowTranslucentStatus">...</item>
  <item name="android:windowTranslucentNavigation">...</status>
</style>

如果您的应用采用无边框显示,请勿对系统栏的大小、数量、类型或位置做出假设。而是应使用窗口边衬区 API,相对于系统栏来布置应用的内容。如需详细了解如何使用这些 API,请参阅在应用中全屏显示内容。不建议对任何设备规格使用硬编码内边距值,但在汽车中,这些值可能根本无法将内容保留在安全区域内。

适应不规则形状的显示屏

除了矩形显示屏外,某些车辆可能还配备了不规则形状的屏幕,如图 1 所示:

右侧为曲面的 Android Automotive OS 设备显示屏。
图 1:右侧为曲面屏的 Android Automotive OS 设备。绿色区域是安全矩形,不与曲面刘海屏的边界框重叠。

如果您的应用不采用边到边渲染,则您无需执行任何操作即可让其在安全区域内渲染。

如果您的应用采用无边框渲染,您可以选择希望它在刘海屏上如何运行。您可以通过以下方式实现此目的:使用资源为应用的主题设置 android:windowLayoutInDisplayCutoutMode 属性,或在运行时修改窗口的 layoutInDisplayCutoutMode 属性。

由于 Android Automotive OS 设备上的刘海屏类型与移动设备上的不同,因此请勿使用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT 或 LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,因为它们的行为针对移动设备上的刘海屏进行了优化。请改用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER 或 LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS,以便始终避开或始终进入刘海屏区域。如果选择后者,请参阅支持刘海屏,详细了解与刘海屏相关的 API。

如果您的应用会渲染到刘海屏区域,并且您希望 Android Automotive OS 和移动设备之间有不同的行为,请参阅停用功能(如果您的应用在运行时设置此行为)和使用备用资源(如果您的应用使用资源文件设置此行为)获取指导。

停用功能

如果您要将现有移动应用提供给 Android Automotive OS,某些特性和功能可能不相关或不可用。例如,汽车通常不提供对摄像头的访问权限。此外,只有部分 Google Play 服务适用于 Android Automotive OS;如需了解详情,请参阅适用于汽车的 Google Play 服务。

您可以使用 PackageManager.hasSystemFeature API,通过检查有无 FEATURE_AUTOMOTIVE 功能来检测应用是否正在 Android Automotive OS 上运行,如以下示例所示:

val isCar = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
if (isCar) {
    // Enable or disable a given feature
}

或者,如果您的应用还包含 Android Auto 组件,您可以使用 Android for Cars 应用库中的 CarConnection API 来检测应用是在 Android Automotive OS 还是 Android Auto 上运行,还是根本未关联到汽车。

对于画中画 (PiP) 功能,请遵循既有的最佳实践来检查该功能是否可用并做出适当的回应。

处理离线场景

尽管汽车的联网程度越来越高,但我们建议应用具备在没有互联网连接的情况下处理运行的能力,例如以下情况:

  • 用户可能会选择停用汽车制造商提供的订阅套餐中的移动流量服务。
  • 在某些区域,使用移动流量可能会受到限制。
  • 配有 Wi-Fi 无线装置的汽车可能不在 Wi-Fi 覆盖范围内,或者原始设备制造商 (OEM) 可能会停用 Wi-Fi,改为使用移动网络。

请优雅降级依赖于访问互联网的功能(例如提供离线内容),准备好在您的应用中处理这些场景。如需了解详情,请参阅网络优化最佳实践。

使用备用资源

为了有助于您的应用在汽车上运行,当在 Android Automotive OS 车辆上运行时,您可以使用 car 资源限定符提供备用资源。例如,如果您使用尺寸资源来存储内边距值,则可以为 car 资源集使用较大的值,以增大触摸目标。