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를 렌더링할 때 부팅 프로세스 중에 CarService
는 config.xml
의 InstrumentClusterRendererService
키를 읽어서 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 플랫폼에서 제공하는
CarService
및CarNavigationStatusManager
입니다. 자세한 내용은 자동차 및 CAR_NAVIGATION_SERVICE를 참고하세요. - 녹청색. OEM에서 구현하는
InstrumentClusterRendererService
입니다. - 자주색. Google 및 서드 파티 개발자가 구현하는 네비게이션 앱입니다.
- 녹색.
CarAppFocusManager
입니다. 자세한 내용은 아래의 CarAppFocusManager API 사용과 CarAppFocusManager를 참고하세요.
탐색 상태 정보 흐름은 다음 시퀀스를 따릅니다.
CarService
는InstrumentClusterRenderingService
를 초기화합니다.- 초기화 중에
InstrumentClusterRenderingService
는CarService
를 다음으로 업데이트합니다.- 뚜렷한 경계와 같은 Instrument Cluster 디스플레이 속성입니다(나중에 뚜렷한 경계에 관한 자세한 내용 참고).
- Instrument Cluster 디스플레이 내부에서 활동을 시작하는 데 필요한 활동 옵션입니다(ActivityOptions에서 자세한 내용 참고).
- 내비게이션 앱(예: Android Automotive용 Google 지도 또는 필요한 권한을 가진 지도 앱):
- car-lib에서 Car 클래스를 사용하여
CarAppFocusManager
를 가져옵니다. - 세부 경로 안내가 시작되기 전에
CarAppFocusManager.requestFocus()
를 호출하여CarAppFocusManager.APP_FOCUS_TYPE_NAVIGATION
을appType
매개변수로 전달합니다.
- car-lib에서 Car 클래스를 사용하여
CarAppFocusManager
가 이 요청을CarService
에 전달합니다. 권한이 부여된 경우CarService
는 내비게이션 앱 패키지를 검사하고android.car.cluster.NAVIGATION
카테고리로 표시된 활동을 찾습니다.- 찾은 경우 내비게이션 앱은
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 구현
서비스를 빌드하려면:
InstrumentClusterRenderingService
에서 확장되는 클래스를 작성한 다음,AndroidManifest.xml
파일에 상응하는 항목을 추가합니다. 이 클래스는 Instrument Cluster 디스플레이를 제어하며 Navigation State API 데이터를 (필요한 경우) 렌더링할 수 있습니다.onCreate()
중에 이 서비스를 사용하여 렌더링 하드웨어와의 통신을 초기화합니다. 다음과 같은 옵션이 있습니다.- Instrument Cluster에 사용할 보조 디스플레이를 결정합니다.
- Instrument Cluster 앱이 이미지를 렌더링하고 렌더링된 이미지를 외부 단위에 전송(H.264와 같은 동영상 스트리밍 형식 사용)하도록 가상 디스플레이를 만듭니다.
- 위에 표시된 디스플레이가 준비되면 이 서비스는
InstrumentClusterRenderingService#setClusterActivityLaunchOptions()
를 호출하여 Instrument Cluster에서 활동을 표시하는 데 사용해야 하는 정확한ActivityOptions
를 정의해야 합니다. 다음 매개변수를 사용합니다.- category. CarInstrumentClusterManager#CATEGORY_NAVIGATION
ActivityOptions.
Instrument Cluster에서 활동을 시작하는 데 사용할 수 있는ActivityOptions
인스턴스입니다. 예를 들어 AOSP의 샘플 Instrument Cluster 구현에서 시작합니다.getService().setClusterActivityLaunchOptions( CATEGORY_NAVIGATION, ActivityOptions.makeBasic() .setLaunchDisplayId(displayId));
- Instrument Cluster가 활동을 표시할 준비가 되면 이 서비스는
InstrumentClusterRenderingService#setClusterActivityState()
를 호출해야 합니다. 다음 매개변수를 사용합니다.category
CarInstrumentClusterManager#CATEGORY_NAVIGATION
state
ClusterActivityState를 사용하여 생성된 번들입니다. 다음 데이터를 제공해야 합니다.visible
Instrument Cluster를 공개 가능 및 콘텐츠 표시 가능으로 지정합니다.unobscuredBounds
콘텐츠를 안전하게 표시할 수 있는 Instrument Cluster 디스플레이 내 영역을 정의하는 직사각형입니다. 다이얼 및 게이지가 적용되는 영역을 예로 들 수 있습니다.
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를 구현하는 샘플 애플리케이션을 제공합니다.
이 샘플 애플리케이션을 실행하려면:
- 지원되는 HU에서 Android Auto를 빌드하고 플래시합니다. 사용 중인 기기와 관련된 Android 빌드 및 플래시 안내를 사용합니다. 자세한 내용은 참조 보드 사용을 참고하세요.
- 물리적 보조 디스플레이를 HU(지원되는 경우)에 연결하거나 가상 보조 HU를 사용 설정합니다.
- 설정 앱에서 개발자 모드를 선택합니다.
- 설정 > 시스템 > 고급 > 개발자 옵션 > 보조 디스플레이 시뮬레이션으로 이동합니다.
- HU를 재부팅합니다. ClusterRenderingService 서비스가 보조 디스플레이에 연결됩니다.
- KitchenSink 앱을 시작하려면:
- 창을 엽니다.
- Instrument Cluster로 이동합니다.
- 메타데이터 시작을 클릭합니다.
KitchenSink는 NAVIGATION 포커스를 요청합니다. 이 포커스는 DirectRenderingCluster
서비스가 Instrument Cluster에서 모의 사용자 인터페이스를 표시하도록 지시합니다.