檢測叢集 API

使用 Instrument Cluster API (Android API) 顯示導航應用程式。 包括 Google 地圖 (顯示在車上的第二台螢幕上),例如 儀表板上的方向盤。本頁說明如何 服務控制該次要顯示器,以及將服務整合到 CarService,讓導航應用程式可顯示 存取 API

術語

本頁面使用的字詞如下。

CarInstrumentClusterManager
CarManager 的例項,可讓外部應用程式在 檢測叢集,並在儀表板準備就緒時接收回呼 活動。
CarManager
外部應用程式使用的所有管理員的基礎類別,用來與汽車互動 。
CarService
提供外部應用程式通訊的 Android 平台服務 (包括 Google 地圖) 和車輛專用功能,例如儀表板存取權。
到達網頁
車輛行駛的最終目的地。
預計抵達時間 (ETA)
抵達目的地的預估時間。
車用運算主機 (HU)
主要運算單位,內嵌於車內。HU 會執行所有 Android 程式碼, 。
儀表板
方向盤後方和車輛之間的次要螢幕 樂器可以是連結至 透過車輛的內部網路 (CAN 公車) 或次要螢幕,以 HU 移動為準 。
檢測叢集轉譯服務
用來與儀表板互動的服務的基礎類別 螢幕。原始設備製造商 (OEM) 必須提供此類別的擴充功能 原始設備製造商 (OEM) 專屬硬體
KitchenSink 應用程式
測試 Android Automotive 隨附的應用程式。
路線
車輛行駛到目的地的特定路徑。
單例模式服務
具有 android:singleUser 屬性的 Android 服務。在 無論何時,在 Android 系統上最多只能執行一個服務執行個體。

必要條件

繼續操作之前,請務必備妥下列元素:

  • Android 開發環境。如何設定 Android 開發環境的詳細說明,請參閱 建構需求
  • 下載 Android 原始碼。取得最新版本的 從 Pi-car-release 分支版本 (或之後版本) 的 Android 原始碼 https://android.googlesource.com
  • 車用運算主機 (HU)。可執行 搭載 Android 9 以上版本。此裝置必須裝有專屬顯示器,且 利用新版 Android 刷新螢幕
  • 「Instrument Cluster」是下列其中一種:
    • 連接至 HU 的實體次要螢幕。如果 裝置硬體和核心支援管理多個螢幕。
    • 獨立單位。任何連線至 透過網路連線使用 HU,能夠接收和顯示影片串流 獨立的顯示器
    • 模擬顯示畫面。在開發期間,您可以使用 模擬環境:
      • 模擬的次要螢幕。如要啟用模擬功能 任何 Android 開放原始碼計畫 Android 發行版的次要螢幕,請前往「開發人員選項」 「設定」系統應用程式中的設定,然後選取「模擬次要動作」 顯示 此設定等同於附加實體 螢幕,差別在於這個螢幕的限制會疊加在主要畫面上 螢幕。
      • 模擬的儀表板。內附 Android 模擬器 搭配 AAOS 提供選擇顯示檢測儀表板的 ClusterRenderingService

整合架構

整合元件

Instrument Cluster API 的任何整合項目皆由下列三個元件組成:

  • CarService
  • 導航應用程式
  • 原始設備製造商 (OEM) 檢測叢集服務

整合元件

CarService

CarService 會在導航應用程式和車輛之間進行中介,確保只會 只有一個導航應用程式會同時啟用,且只能使用 android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL 權限可傳送資料 。

CarService」會啟動所有車輛專用服務,並提供存取權 我們會提供各式各樣的服務如要與服務互動 運行中的應用程式可存取這些管理員。

如要導入儀表板,汽車原始設備製造商 (OEM) 必須建立自訂 實作 InstrumentClusterRendererService,然後更新 ClusterRenderingService

轉譯檢測叢集時,在啟動程序期間 CarService 會讀取InstrumentClusterRendererService ClusterRenderingService 找出 InstrumentClusterService 的實作。在 Android 開放原始碼計畫中,這個項目 指向 Navigation State API 範例叢集實作轉譯服務:

<string name="instrumentClusterRendererService">
android.car.cluster/.ClusterRenderingService
</string>

這個項目中參照的服務經過初始化並繫結至 CarService。導航應用程式 (例如 Google 地圖) 時要求 CarInstrumentClusterManagerCarService 提供的管理員 從繫結的 InstrumentClusterRenderingService 更新檢測叢集狀態。 (在本例中,bound 是指 Android 版 服務)

儀表板服務

原始設備製造商 (OEM) 必須建立 Android 套件 (APK),其中包含 ClusterRenderingService

這個類別有兩個用途:

  • 提供 Android 介面和「Instrument Cluster」轉譯裝置 (本頁目的)。
  • 接收及呈現導航狀態更新,例如即時路線 導航指引。

針對第一個用途,原始設備製造商 (OEM) 的 InstrumentClusterRendererService 實作 必須初始化次要顯示器,用來在車櫃的螢幕上呈現資訊,並 藉由呼叫CarService InstrumentClusterRendererService.setClusterActivityOptions()InstrumentClusterRendererService.setClusterActivityState() 方法。

如果是第二個函式,檢測叢集服務必須提供 導入 ClusterRenderingService 接收導覽狀態更新「事件」的介面,這類事件會編碼為 透過套件編碼的 eventType 和事件資料。

整合序列

下圖說明導覽狀態的實作 轉譯更新的內容:

整合序列

在本圖中,顏色代表的意義如下:

  • 黃色。CarService」和「CarNavigationStatusManager」 Android 平台提供的功能詳情請參閱: CarCAR_NAVIGATION_SERVICE
  • 青色已導入 InstrumentClusterRendererService
  • 紫色。由 Google 和第三方實作的導航應用程式 開發人員。
  • 綠色。跳到 CarAppFocusManager 的位置。詳情請參閱: 使用 CarAppFocusManager API 下方和 CarAppFocusManager

導覽狀態資訊流程會遵循以下順序:

  1. CarService 會初始化 InstrumentClusterRenderingService
  2. 在初始化期間,InstrumentClusterRenderingService 會更新 CarService,其中包含:
    1. 儀表板顯示屬性,例如未模糊邊界 (稍後查看更多未模糊界線的詳細資料)。
    2. 透過儀表板螢幕啟動活動所需的活動選項。 詳情請參閱: ActivityOptions
  3. 導航應用程式 (例如 Android Automotive 專用的 Google 地圖,或任何地圖應用程式 並授予必要權限):
    1. 使用 Car-lib 中的 Car 類別取得 CarAppFocusManager
    2. 即時路線導航開始之前,如果: 通過 CarAppFocusManager.requestFocus()CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION做為appType 參數。
  4. CarAppFocusManager 將這項要求傳送給 CarService。 如果獲授予,CarService 會檢查導航應用程式套件,然後找出 活動已標示 android.car.cluster.NAVIGATION 類別。
  5. 如果找到,導航應用程式會使用以下指標回報的 ActivityOptions: 使用 InstrumentClusterRenderingService 來啟動活動,並包含 在意圖中,檢測叢集顯示屬性做為額外項目。

整合 API

InstrumentClusterRenderingService 實作必須:

  • 將下列值新增至單例模式服務 AndroidManifest.xml 檔案有效確保 即使在初始化和使用者切換期間,仍會檢測叢集服務:
    android:singleUser="true"
  • 保留 BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE 系統權限。這個 保證只有儀表板轉譯服務隨附在 的 Android 系統映像檔已與 CarService 繫結:
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

實作 InstrumentClusterRenderingService

如要建構服務:

  1. 編寫可擴充的類別 ClusterRenderingService 並將對應的項目新增至 AndroidManifest.xml 檔案。本課程 控制儀表板螢幕,並可 (選用) 轉譯導覽狀態 API 資料。
  2. onCreate() 期間,使用此服務初始化與 轉譯硬體選項包括:
    • 決定檢測叢集要使用的次要螢幕。
    • 建立虛擬螢幕,讓「Instrument Cluster」應用程式顯示及傳輸 將圖像算繪至外部單位 (使用 H.264 等影片串流格式)。
  3. 上述螢幕準備就緒時,該服務必須呼叫 InstrumentClusterRenderingService#setClusterActivityLaunchOptions(): 在顯示活動時,必須用來ActivityOptions 儀表板。使用下列參數:
    • category. ClusterRenderingService
    • ActivityOptions. 可選用的 ActivityOptions 執行個體 用來在儀表板中啟動活動例如 在 Android 開放原始碼計畫中檢測叢集實作:
      getService().setClusterActivityLaunchOptions(
        CATEGORY_NAVIGATION,
        ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. 當儀表叢集準備好顯示活動時,此服務必須叫用 InstrumentClusterRenderingService#setClusterActivityState()。使用這些 參數:
    • category ClusterRenderingService
    • 已產生 state 套組 ClusterRenderingService。 請務必提供以下資料:
      • visible 將檢測叢集指定為可見,且可供使用 顯示內容。
      • unobscuredBounds 用來定義 用於儀表板螢幕,可顯示內容可以安全顯示。舉例來說 能遮蔽用電器和測量儀表板
  5. 覆寫 Service#dump() 方法,並回報適合以下項目的狀態資訊: 偵錯 (請參閱 dumpsys 的說明)。

InstrumentClusterRenderingService 實作範例

以下範例說明 InstrumentClusterRenderingService 實作,建立 VirtualDisplay 以顯示檢測設備 在遠端實體螢幕上將內容叢集化。

或者,此程式碼也可以傳遞實體次要函式的 displayId 電腦連接到 HU (如果有的話)。

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display to be used for instrument
   // cluster
   private final String mUniqueId = UUID.randomUUID().toString();
   // Format of the instrument cluster display
   private static final int DISPLAY_WIDTH = 1280;
   private static final int DISPLAY_HEIGHT = 720;
   private static final int DISPLAY_DPI = 320;
   // Area not covered by instruments
   private static final int DISPLAY_UNOBSCURED_LEFT = 40;
   private static final int DISPLAY_UNOBSCURED_TOP = 0;
   private static final int DISPLAY_UNOBSCURED_RIGHT = 1200;
   private static final int DISPLAY_UNOBSCURED_BOTTOM = 680;
   @Override
   public void onCreate() {
      super.onCreate();
      // Create a virtual display to render instrument cluster activities on
      mDisplayManager = getSystemService(DisplayManager.class);
      VirtualDisplay display = mDisplayManager.createVirtualDisplay(
          mUniqueId, DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_DPI, null,
          0 /* flags */, null, null);
      // Do any additional initialization (e.g.: start a video stream
      // based on this virtual display to present activities on a remote
      // display).
      onDisplayReady(display.getDisplay());
}
private void onDisplayReady(Display display) {
    // Report activity options that should be used to launch activities on
    // the instrument cluster.
    String category = CarInstrumentClusterManager.CATEGORY_NAVIGATION;
    ActionOptions options = ActivityOptions.makeBasic()
        .setLaunchDisplayId(display.getDisplayId());
    setClusterActivityOptions(category, options);
    // Report instrument cluster state.
    Rect unobscuredBounds = new Rect(DISPLAY_UNOBSCURED_LEFT,
        DISPLAY_UNOBSCURED_TOP, DISPLAY_UNOBSCURED_RIGHT,
        DISPLAY_UNOBSCURED_BOTTOM);
    boolean visible = true;
    ClusterActivityState state = ClusterActivityState.create(visible,
       unobscuredBounds);
    setClusterActivityState(category, options);
  }
}

使用 CarAppFocusManager API

CarAppFocusManager API 提供名為 getAppTypeOwner() 的方法,讓 執行原始設備製造商 (OEM) 編寫的叢集服務,以瞭解哪個導航應用程式在任何指定位置都有瀏覽焦點 讓應用程式從可以最快做出回應的位置 回應使用者要求原始設備製造商 (OEM) 可使用現有的 CarAppFocusManager#addFocusListener() 方法,以及 然後使用 getAppTypeOwner() 瞭解哪些應用程式有焦點。有了這些資訊 原始設備製造商 (OEM) 可以:

  • 將叢集中顯示的活動切換至導航應用程式提供的叢集活動 正在保留焦點。
  • 可偵測焦點導覽應用程式是否有叢集活動。如果焦點已聚焦 導航應用程式沒有叢集活動 (或這類活動已停用),原始設備製造商 (OEM) 可以 將這個信號傳送到汽車 DIM,這樣就能完全略過叢集的導航面向。

使用 CarAppFocusManager 即可設定及監聽目前的應用程式焦點,例如 主動導航或語音指令通常這類應用程式只有一個, 系統中執行 (或聚焦) 的程序。

使用 CarAppFocusManager#addFocusListener(..) 方法監聽應用程式焦點 變更:

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
mAppFocusManager.addFocusListener(this, CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

...

public void onAppFocusChanged(int appType, boolean active) {
    // Use the CarAppFocusManager#getAppTypeOwner(appType) method call
    // to retrieve a list of active package names
}

使用 CarAppFocusManager#getAppTypeOwner(..) 方法擷取套件 關注的特定應用程式類型目前擁有者的名稱。這個方法可能會傳回 如果目前擁有者使用 android:sharedUserId 功能,就會有多個套件名稱。

import android.car.CarAppFocusManager;

...

Car car = Car.createCar(this);
mAppFocusManager = (CarAppFocusManager)car.getCarManager(Car.APP_FOCUS_SERVICE);
List<String> focusOwnerPackageNames = mAppFocusManager.getAppTypeOwner(
              CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION);

if (focusOwnerPackageNames == null || focusOwnerPackageNames.isEmpty()) {
        // No Navigation app has focus
        // OEM may choose to show their default cluster view
} else {
       // focusOwnerPackageNames
       // Use the PackageManager to retrieve the cluster activity for the package(s)
       // returned in focusOwnerPackageNames
}

...

附錄:使用範例應用程式

Android 開放原始碼計畫提供實作 Navigation State API 的範例應用程式。

如要執行這個範例應用程式:

  1. 在支援的 HU 上建構 Android Auto 並刷新。使用 您裝置專屬的 Android 建構和刷新指示。如需指示,請參閱: 使用參考板
  2. 將實體次要螢幕連接至 HU (如果支援的話),或開啟虛擬 次要 HU:
    1. 在「設定」應用程式中選取「開發人員模式」
    2. 前往「設定」>系統 >進階 >開發人員選項 > 模擬次要螢幕
  3. 重新啟動 HU
  4. 如要啟動 KitchenSink 應用程式:
    1. 開啟導覽匣。
    2. 前往「Inst.叢集
    3. 按一下「開始中繼資料」

KitchenSink 要求 NAVIGATION 焦點時,會指示 DirectRenderingCluster 以在儀表板上顯示模擬使用者介面的使用者介面。