向停车状态下使用的应用添加 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-2DD-3 质量指南中所述。

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

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

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

如果应用中的 activity 在用户体验限制生效时处于 Resumed 状态,则会被操作系统拥有的 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 来显示或隐藏系统栏时,不会发生任何情况。请参阅 showhide 的文档,详细了解如何检测应用是否能够修改边衬区。

同样,原始设备制造商 (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_DEFAULTLAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES,因为它们的行为针对移动设备上的刘海屏进行了优化。请改用 LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVERLAYOUT_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 资源集使用较大的值,以增大触摸目标。