自定义应用程序

现在,汽车 UI 库组件和资源已集成到应用程序中,为了自定义这些应用程序,OEM 必须提供两个覆盖层:

  • 构建时覆盖添加运行时资源覆盖 (RRO) 所需的任何资源。这包括:

    • 绘图
    • 样式(例如,文本外观)
    • 共享资源(例如颜色)
  • RRO 覆盖文件夹包含用于为每个目标应用程序生成一个 RRO 的资源。这些资源只能参考:

    • 在同一 RRO 中定义的值(例如,对于颜色,这将是十六进制值)。
    • Android 框架资源(例如@android:color/accent )。
    • 在上面的构建时覆盖中定义的资源。

总体结构

建议的定制覆盖结构如下:

  • <path-to-OEM-overlays>/

    • overlay/framework/base/core/res/ 。构建时覆盖资源

    • rro/

      • Android.mk 。 Makefile 用于根据此文件夹中包含的资源为每个目标包生成 RRO。

      • AndroidManifest.xml 。上述 makefile 使用的清单文件模板。

      • res/ 。运行时覆盖适用于所有目标应用程序。

OEM 可能拥有多个这些结构,具体取决于他们想要在单个构建目标中处理的品牌数量(请参阅处理多个品牌)。

运行时资源覆盖

OEM 覆盖文件夹中的 RRO 文件夹应包含要应用于所有目标应用程序的资源。 RRO 存在一些限制,影响其覆盖复合资源的能力。总之,RRO:

  • 无法引用目标 APK 或 RRO 本身中定义的资源标识符。这意味着 RRO 无法添加新的标识符,例如新的绘图、颜色或样式。

  • 引用框架中定义的资源标识符,无论这些资源是在/frameworks/base/core/res中定义还是通过构建时覆盖定义。这些标识符必须使用android:命名空间引用:

    • 对于公共DeviceDefault RRO,请使用android
      例如, @android:style/TextAppearance.DeviceDefault.Large

    • 对于所有其他资源(非公共资源或通过构建时覆盖添加的资源),请使用*android
      例如, @*android/style:TextAppearance.OEM.Brand1.Title

除了资源之外,RRO 文件夹还必须包含:

  • AndroidManifest.xml 。在下面的示例中, RRO_PACKAGE_NAMETARGET_PACKAGE_NAME是 makefile 的占位符:

    <?xml version=“1.0” encoding=“utf-8”?>
    <manifest xmlns:android=“http://schemas.android.com/apk/res/android”
        package=“{{RRO_PACKAGE_NAME}}” />
        <application android:hasCode=“false” />
        <overlay android:priority=“10”
            android:targetPackage=“{{TARGET_PACKAGE_NAME}}”
            android:requiredSystemPropertyName=“ro.product.sku”
            android:requiredSystemPropertyValue=“<your-product-sku>” />
    </manifest>
    
  • Android.mk ,其中以下 makefile 中的oem定义所有生成的 RRO 将具有的前缀。
      LOCAL_PATH := $(call my-dir)
      include $(CLEAR_VARS)
      CAR_UI_RRO_SET_NAME := oem
      CAR_UI_RESOURCE_DIR := $(LOCAL_PATH)/res
      CAR_UI_RRO_TARGETS := $(CAR_UI_RRO_PACKAGE_NAMES)
      include packages/apps/Car/libs/car-ui-lib/generate_rros.mk
      

配置 RRO

支持新的配置文件, overlayable.xml ,您可以使用它来定义访问控制。例如,您可以指定谁可以覆盖资源以及可以覆盖哪些资源。因此,现在可以以不同的方式对资源进行分组,以便可以由不同的 RRO 覆盖。

设置 RRO 访问控制:

  1. res/values文件夹中,创建overlayable.xml
  2. 创建<overlayable>资源标签。
  3. 定义<overlayable>标签的name属性,该属性在包中必须是唯一的。每个覆盖只能定位一个可覆盖组。
  4. <overlayable>内定义<policy>标记。
  5. 定义可以叠加的资源组。例如:
      <resources>
          <overlayable name="OverlayableResources">
              <policy type="public">
                  <item type="string" name="app_title" />
              </policy>
          </overlayable>
      </resources>
      

要将以下更改应用到您的 RRO 项目:

  1. res/xml文件夹中,创建overlays.xml 。请参阅下面代码示例中的overlay条目。
  2. 定义要覆盖的资源。
  3. android:resourcesMap="@xml/overlays"添加到AndroidManifest.xml中的<overlay>标记。例如,在下面的代码示例中,请参阅<overlay>条目。
  4. 设置android:isStatic=”true”为静态覆盖。每个覆盖只能定位可覆盖的组之一。

考虑以下示例。第一部分属于AndroidManifest.xml ,而第二部分属于overlays.xml

  <manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.car.ui.rro"
      android:versionCode="1"
      android:versionName="1.0">
      <overlay android:targetName="OverlayableResources"
               android:resourcesMap="@xml/overlays"
               android:targetPackage="com.android.car.ui"
               android:priority="1"
               android:isStatic="false" />
  </manifest>
  <overlay>
      <item target="string/app_title" value="@ string/app_title" />
  </overlay>
  

但有一点需要注意的是,以前存在的 RRO 可在 Android 10 中使用。需要注意的是,要与 PackageManagerRRO 一起安装,软件包必须预先安装或使用与目标应用程序相同的密钥进行签名。在Android 10中,布局文件可以叠加。但是,这样做需要在获取视图时使用requireViewById()而不是findViewById() 。在 Android 10 中,此更改已在 car-ui-lib 中实现,以支持布局叠加。

Android 的下一个主要版本将使您能够覆盖布局文件并在 RRO 包中定义新资源并在内部引用它们。

添加 OEM 特定资源

要克服阻止添加 OEM 资源的 RRO 限制:

  • 使用构建时覆盖扩展框架/基础,添加任何必要的资源。
  • 使用*android:命名空间从 OEM RRO 引用这些资源。

例如,以下是添加 OEM 特定可绘制对象并在 RRO 中使用它的方法:

  • <path-to-OEM-overlays>

    • overlay/framework/base/core/res/res/drawable/

      • oem_background_drawable.xml

    • rro/res/values

      • drawables.xml

        <resources>
            <item type="drawable" name="car_ui_toolbar_background">
                @*android:drawable/oem_background_drawable
            </item>
        </resources>
        

经营多个品牌

RRO 清单文件具有允许根据系统属性有条件地应用它们的语法。要在单个系统映像中处理多个品牌,OEM 可以按如下方式使用它(请参阅一般结构)。

<?xml version=“1.0” encoding=“utf-8”?>
<manifest xmlns:android=“http://schemas.android.com/apk/res/android”
    package=“{{RRO_PACKAGE_NAME}}”/>
    <application android:hasCode=“false”/>
    <overlay android:priority=“10”
        android:targetPackage=“{{TARGET_PACKAGE_NAME}}”
        android:requiredSystemPropertyName=“ro.product.sku”
        android:requiredSystemPropertyValue=“<your-product-sku>”/>
</manifest>

android:requiredSystemPropertyNameandroid:requiredSystemPropertyValue语法将导致当相应的系统属性与提供的值匹配时启用此 RRO。然后,OEM 可以定义多个 RRO,所有这些 RRO 均静态启用,并且一次只有一个处于活动状态。

将汽车 UI 库添加到目标

要将 Car UI 库合并到 Android 目标中,您必须包含以下代码片段:

# Include build-time overlays
    PRODUCT_PACKAGE_OVERLAYS += \
      <path-to-oem-overlays>/overlay
    # Define package names to generate RROs for
    CAR_UI_RRO_PACKAGE_NAMES += \
      com.android.car.ui.paintbooth \
      com.android.car.media \
      com.android.car.dialer \
      com.android.car.linkviewer \
      com.android.car.settings \
      com.android.car.systemupdater \
      com.google.android.apps.automotive.inputmethod \
      com.google.android.apps.automotive.templates.host \
      ...
    # Include generated RROs
    PRODUCT_PACKAGES += \
      oem-com-android-car-ui-paintbooth \
      oem-com-android-car-media \
      oem-com-android-car-dialer \
      oem-com-android-car-linkviewer \
      oem-com-android-car-settings \
      oem-com-android-car-systemupdater \
      oem-com-google-android-apps-automotive-inputmethod \
      oem-com-google-android-apps-automotive-templates-host \
      ...
  • 导致<path-to-OEM-overlays>/rro/Android.mkCAR_UI_RRO_PACKAGE_NAMES中指定的每个包生成一个 RRO。

  • 将生成的 RRO 包含在PRODUCT_PACKAGES中。

  • PRODUCT_PACKAGE_OVERLAYS中包含构建时覆盖,以添加特定于 OEM 的资源。

要了解哪些软件包支持car-ui-lib ,请参阅包含 car-ui-lib 的软件包列表