Instrument Cluster

Instrument Cluster API(Android API)를 사용하여 Google 지도를 포함한 내비게이션 앱을 자동차의 보조 디스플레이(예: 핸들 뒤의 계기판)에 표시합니다. 이 페이지에서는 보조 디스플레이를 제어하는 서비스를 만든 다음, 내비게이션 앱이 사용자 인터페이스를 표시할 수 있도록 서비스를 CarService와 통합하는 방법을 설명합니다.

용어

이 페이지에서 사용되는 용어는 다음과 같습니다.

용어 설명
CarInstrumentClusterManager 외부 앱이 Instrument Cluster에서 활동을 시작하고 Instrument Cluster가 활동을 표시할 수 있을 때 콜백을 수신하도록 하는 CarManager입니다.
CarManager 외부 앱이 CarService에서 구현되는 자동차 관련 서비스와 상호작용하는 데 사용되는 모든 관리자의 기본 클래스입니다.
CarService 외부 앱(Google 지도 포함)과 자동차 관련 기능(예: Instrument Cluster 액세스) 간에 통신을 제공하는 Android 플랫폼 서비스입니다.
목적지 차량이 이동할 최종 목적지입니다.
ETA 목적지 도착 예정 시간입니다.
헤드 단위(HU) 자동차에 삽입된 기본 전산 단위입니다. HU는 모든 Android 코드를 실행하며 자동차의 중앙 디스플레이에 연결됩니다.
Instrument Cluster 핸들 뒤 자동차 계기 사이에 있는 보조 디스플레이입니다. 이는 자동차의 내부 네트워크(CAN 버스)를 통해 HU에 연결된 독립적인 전산 단위이거나 HU에 연결된 보조 디스플레이일 수 있습니다.
InstrumentClusterRenderingService Instrument Cluster 디스플레이와 상호연결하는 데 사용되는 서비스의 기본 클래스입니다. OEM은 OEM별 하드웨어와 상호작용하는 이 클래스의 확장 프로그램을 제공해야 합니다.
KitchenSink 앱 Android Automotive에 포함된 테스트 애플리케이션입니다.
경로 차량이 목적지에 도착하기 위해 이동하는 구체적인 경로입니다.
싱글톤 서비스 android:singleUser 속성이 있는 Android 서비스입니다. 언제든지 최대 1개의 서비스 인스턴스가 Android 시스템에서 실행됩니다.

기본 요건

통합을 개발하려면 다음 요소가 있어야 합니다.

  • Android 개발 환경. Android 개발 환경을 설정하려면 빌드 요구사항을 참고하세요.
  • Android 소스 코드 다운로드. pi-car-release 브랜치의 최신 Android 소스 코드 버전(또는 이상)을 https://android.googlesource.com에서 가져옵니다.
  • HU(헤드 단위). Android 9 이상을 실행할 수 있는 Android 기기입니다. 이 기기에는 자체 디스플레이가 있어야 하며 새로운 Android 빌드로 디스플레이를 플래시할 수 있어야 합니다.
  • Instrument Cluster는 다음 중 하나입니다.
    • HU에 연결된 물리적 보조 디스플레이. 기기 하드웨어 및 커널이 여러 디스플레이의 관리를 지원하는 경우입니다.
    • 독립적인 단위. 네트워크 연결을 통해 HU에 연결된 전산 단위로, 자체 디스플레이에서 동영상 스트림을 수신하고 표시할 수 있습니다.
    • 에뮬레이션된 디스플레이. 개발 중에 다음 에뮬레이션된 환경 중 하나를 사용할 수 있습니다.
      • 시뮬레이션된 보조 디스플레이. AOSP Android 배포에서 시뮬레이션된 보조 디스플레이를 사용 설정하려면 설정 시스템 애플리케이션의 개발자 옵션 설정으로 이동한 다음, 보조 디스플레이 시뮬레이션을 선택합니다. 이 구성은 물리적 보조 디스플레이를 연결하는 것과 같으며, 이 디스플레이가 기본 디스플레이에 중첩된다는 제한이 있습니다.
      • 에뮬레이션된 계기판. Android Automotive에 포함된 Android Emulator는 Android 에뮬레이터 _qemu-pipes를 통해 계기판을 표시하는 옵션을 제공합니다. DirectRenderingClusterSample 참조 계기판 구현을 사용하여 에뮬레이션된 외부 디스플레이에 연결합니다.

통합 아키텍처

통합 구성요소

Instrument Cluster API 통합은 다음 3개 구성요소로 구성됩니다.

  • CarService
  • 내비게이션 앱
  • OEM Instrument Cluster 서비스

통합 구성요소

CarService

CarService는 내비게이션 앱과 자동차 간에 중재하여 언제든지 하나의 내비게이션 앱만 활성화되고 android.car.permission.CAR_INSTRUMENT_CLUSTER_CONTROL 권한이 있는 앱만 자동차에 데이터를 보낼 수 있도록 합니다.

CarService는 모든 자동차 관련 서비스를 부트스트랩하고 일련의 관리자를 통해 관련 서비스에 액세스할 수 있는 권한을 제공합니다. 서비스와 상호작용하기 위해 자동차에서 실행되는 애플리케이션은 이러한 관리자에 액세스할 수 있습니다.

계기판 구현의 경우 자동차 OEM은 InstrumentClusterRendererService의 맞춤 구현을 만들고 이 맞춤설정된 구현을 가리키도록 config.xml 파일을 업데이트해야 합니다.

Instrument Cluster를 렌더링할 때 부팅 프로세스 중에 CarServiceconfig.xmlInstrumentClusterRendererService 키를 읽어서 InstrumentClusterService 구현을 찾습니다. AOSP에서 이 항목은 Navigation State API 샘플 클러스터 구현 렌더링 서비스를 가리킵니다.

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

이 항목에서 참조된 서비스는 초기화되고 CarService에 바인드됩니다. Google 지도와 같은 내비게이션 앱이 CarInstrumentClusterManager를 요청하면 CarService는 바인드된 InstrumentClusterRenderingService에서 Instrument Cluster 상태를 업데이트하는 관리자를 제공합니다. 이 경우 바인드Android 서비스를 나타냅니다.

Instrument Cluster 서비스

OEM은 InstrumentClusterRendererService.의 서브클래스가 포함된 APK(Android Package)를 만들어야 합니다. 샘플은 ClusterRenderingService를 참고하세요.

이 클래스는 다음 두 가지 목적으로 사용됩니다.

  • Android와 Instrument Cluster 렌더링 기기 간에 인터페이스를 제공합니다(이 페이지의 목적).
  • 세부 경로 안내 탐색 지침과 같은 탐색 상태 업데이트를 수신하고 렌더링합니다.

첫 번째 목적으로, InstrumentClusterRendererService의 OEM 구현은 차량 실내에서 화면에 정보를 렌더링하고 InstrumentClusterRendererService.setClusterActivityOptions()InstrumentClusterRendererService.setClusterActivityState() 메서드를 호출하여 이 정보를 CarService에 전달하는 데 사용되는 보조 디스플레이를 초기화해야 합니다.

두 번째 기능을 위해 Instrument Cluster 서비스는 eventType으로 인코딩되는 탐색 상태 업데이트 이벤트 및 번들로 인코딩된 이벤트 데이터를 수신하는 NavigationRenderer 인터페이스의 구현을 제공해야 합니다.

통합 시퀀스

다음 다이어그램은 업데이트를 렌더링하는 탐색 상태의 구현을 보여 줍니다.

통합 시퀀스

이 삽화에서 색상은 다음을 나타냅니다.

  • 노란색. Android 플랫폼에서 제공하는 CarServiceCarNavigationStatusManager입니다. 자세한 내용은 자동차CAR_NAVIGATION_SERVICE를 참고하세요.
  • 녹청색. OEM에서 구현하는 InstrumentClusterRendererService입니다.
  • 자주색. Google 및 서드 파티 개발자가 구현하는 네비게이션 앱입니다.
  • 녹색. CarAppFocusManager입니다. 자세한 내용은 아래의 CarAppFocusManager API 사용CarAppFocusManager를 참고하세요.

탐색 상태 정보 흐름은 다음 시퀀스를 따릅니다.

  1. CarServiceInstrumentClusterRenderingService를 초기화합니다.
  2. 초기화 중에 InstrumentClusterRenderingServiceCarService를 다음으로 업데이트합니다.
    1. 뚜렷한 경계와 같은 Instrument Cluster 디스플레이 속성입니다(나중에 뚜렷한 경계에 관한 자세한 내용 참고).
    2. Instrument Cluster 디스플레이 내부에서 활동을 시작하는 데 필요한 활동 옵션입니다(ActivityOptions에서 자세한 내용 참고).
  3. 내비게이션 앱(예: Android Automotive용 Google 지도 또는 필요한 권한을 가진 지도 앱):
    1. car-lib에서 Car 클래스를 사용하여 CarAppFocusManager를 가져옵니다.
    2. 세부 경로 안내가 시작되기 전에 CarAppFocusManager.requestFocus()를 호출하여 CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATIONappType 매개변수로 전달합니다.
  4. CarAppFocusManager가 이 요청을 CarService에 전달합니다. 권한이 부여된 경우 CarService는 내비게이션 앱 패키지를 검사하고 android.car.cluster.NAVIGATION 카테고리로 표시된 활동을 찾습니다.
  5. 찾은 경우 내비게이션 앱은 InstrumentClusterRenderingService에서 보고한 ActivityOptions를 사용하여 활동을 시작하고 Instrument Cluster 디스플레이 속성을 인텐트에 extras로 포함합니다.

API 통합

InstrumentClusterRenderingService 구현은 다음을 충족해야 합니다.

  • AndroidManifest.xml에 다음 값을 추가하여 싱글톤 서비스로 지정되어야 합니다. 초기화 및 사용자 전환 중에도 Instrument Cluster 서비스의 단일 복사본이 실행되도록 하려면 이 작업이 필요합니다.
    android:singleUser="true"
  • BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE 시스템 권한을 보유해야 합니다. 이렇게 하면 Android 시스템 이미지의 일부로 포함된 Instrument Cluster 렌더링 서비스만 CarService에 바인드됩니다.
    <uses-permission android:name="android.car.permission.BIND_INSTRUMENT_CLUSTER_RENDERER_SERVICE"/>
    

InstrumentClusterRenderingService 구현

서비스를 빌드하려면:

  1. InstrumentClusterRenderingService에서 확장되는 클래스를 작성한 다음, AndroidManifest.xml 파일에 상응하는 항목을 추가합니다. 이 클래스는 Instrument Cluster 디스플레이를 제어하며 Navigation State API 데이터를 (필요한 경우) 렌더링할 수 있습니다.
  2. onCreate() 중에 이 서비스를 사용하여 렌더링 하드웨어와의 통신을 초기화합니다. 다음과 같은 옵션이 있습니다.
    • Instrument Cluster에 사용할 보조 디스플레이를 결정합니다.
    • Instrument Cluster 앱이 이미지를 렌더링하고 렌더링된 이미지를 외부 단위에 전송(H.264와 같은 동영상 스트리밍 형식 사용)하도록 가상 디스플레이를 만듭니다.
  3. 위에 표시된 디스플레이가 준비되면 이 서비스는 InstrumentClusterRenderingService#setClusterActivityLaunchOptions()를 호출하여 Instrument Cluster에서 활동을 표시하는 데 사용해야 하는 정확한 ActivityOptions를 정의해야 합니다. 다음 매개변수를 사용합니다.
    • category. CarInstrumentClusterManager#CATEGORY_NAVIGATION
    • ActivityOptions. Instrument Cluster에서 활동을 시작하는 데 사용할 수 있는 ActivityOptions 인스턴스입니다. 예를 들어 AOSP의 샘플 Instrument Cluster 구현에서 시작합니다.
      getService().setClusterActivityLaunchOptions(
         CATEGORY_NAVIGATION,
         ActivityOptions.makeBasic()
            .setLaunchDisplayId(displayId));
  4. Instrument Cluster가 활동을 표시할 준비가 되면 이 서비스는 InstrumentClusterRenderingService#setClusterActivityState()를 호출해야 합니다. 다음 매개변수를 사용합니다.
    • category CarInstrumentClusterManager#CATEGORY_NAVIGATION
    • state ClusterActivityState를 사용하여 생성된 번들입니다. 다음 데이터를 제공해야 합니다.
      • visible Instrument Cluster를 공개 가능 및 콘텐츠 표시 가능으로 지정합니다.
      • unobscuredBounds 콘텐츠를 안전하게 표시할 수 있는 Instrument Cluster 디스플레이 내 영역을 정의하는 직사각형입니다. 다이얼 및 게이지가 적용되는 영역을 예로 들 수 있습니다.
  5. Service#dump() 메서드를 재정의하고 디버깅에 유용한 상태 정보를 보고합니다(자세한 내용은 dumpsys 참고).

샘플 InstrumentClusterRenderingService 구현

다음 예에서는 원격 물리적 디스플레이에 Instrument Cluster 콘텐츠를 표시할 VirtualDisplay를 만드는 InstrumentClusterRenderingService 구현을 개략적으로 보여 줍니다.

또는 이 코드는 HU에 연결된 물리적 보조 디스플레이의 displayId를 전달할 수 있습니다(사용 가능한 것으로 알려진 경우).

/**
* Sample {@link InstrumentClusterRenderingService} implementation
*/
public class SampleClusterServiceImpl extends InstrumentClusterRenderingService {
   // Used to retrieve or create displays
   private final DisplayManager mDisplayManager;
   // Unique identifier for the display that will 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 application 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
}

...

부록: 샘플 애플리케이션 사용

AOSP는 Navigation State API를 구현하는 샘플 애플리케이션을 제공합니다.

이 샘플 애플리케이션을 실행하려면:

  1. 지원되는 HU에서 Android Auto를 빌드하고 플래시합니다. 사용 중인 기기와 관련된 Android 빌드 및 플래시 안내를 사용합니다. 자세한 내용은 참조 보드 사용을 참고하세요.
  2. 물리적 보조 디스플레이를 HU(지원되는 경우)에 연결하거나 가상 보조 HU를 사용 설정합니다.
    1. 설정 앱에서 개발자 모드를 선택합니다.
    2. 설정 > 시스템 > 고급 > 개발자 옵션 > 보조 디스플레이 시뮬레이션으로 이동합니다.
  3. HU를 재부팅합니다. ClusterRenderingService 서비스가 보조 디스플레이에 연결됩니다.
  4. KitchenSink 앱을 시작하려면:
    1. 창을 엽니다.
    2. Instrument Cluster로 이동합니다.
    3. 메타데이터 시작을 클릭합니다.

KitchenSink는 NAVIGATION 포커스를 요청합니다. 이 포커스는 DirectRenderingCluster 서비스가 Instrument Cluster에서 모의 사용자 인터페이스를 표시하도록 지시합니다.