자동차용 Android 앱 라이브러리 사용

자동차용 Android 앱 라이브러리 내비게이션, 관심 장소 (POI), 사물 인터넷 (IOT)을 가져올 수 있습니다. 차량에 앱을 배포합니다. 운전자 주의 분산 행동을 해결하도록 설계된 일련의 템플릿을 제공하여 이를 실현합니다. 다양한 자동차 화면 요인과 같은 세부사항을 고려하고 있습니다. 입력 모달리티 등이 있습니다

이 가이드에서는 라이브러리의 주요 기능과 개념을 간략히 살펴보고 에서는 기본 앱을 설정하는 과정을 안내합니다.

시작하기 전에

  1. 운전을 위한 디자인 검토 자동차 앱 라이브러리를 다루는 페이지 <ph type="x-smartling-placeholder">
  2. 다음 문서의 주요 용어 및 개념을 검토하세요. 섹션으로 이동합니다.
  3. Android Auto 시스템 숙지 UIAndroid Automotive OS 설계를 참고하세요.
  4. 출시 노트를 검토합니다.
  5. 샘플을 검토합니다.

주요 용어 및 개념

모델 및 템플릿
사용자 인터페이스는 다양한 방식으로 구현될 수 있는 모델 객체의 그래프로 표현 속한 템플릿에서 허용하는 대로 다른 방식으로 정렬되어야 합니다. 있습니다. 템플릿은 모델에서 루트 역할을 할 수 있는 모델의 하위 집합입니다. 그래프로 표현할 수 있습니다. 모델에는 텍스트, 이미지, 속성의 측면을 구성하는 정보의 시각적 모양(예: 텍스트 색상 또는 이미지) 있습니다. 호스트는 모델을 다음과 같은 요구사항을 충족하도록 설계된 뷰로 변환합니다. 운전자 주의 분산 행동 표준과 다양한 세세한 부분까지 입력 모달리티에 관한 것입니다.
호스트
호스트는 제공되는 기능을 구현하는 백엔드 구성요소입니다. 자동차에서 앱이 실행될 수 있도록 합니다. 이 호스트의 역할은 앱 검색부터 관리, 모델을 뷰로 변환하고 앱에 알리기 위한 수명 주기 중요한 역할을 합니다 휴대기기에서 이 호스트는 Android로 구현됩니다. 자동 Android Automotive OS에서 이 호스트는 시스템 앱으로 설치됩니다.
템플릿 제한사항
다양한 템플릿이 모델의 콘텐츠에 제한을 적용합니다. 대상 예를 들어 목록 템플릿에는 사용자에게 표시됩니다. 또한 템플릿은 작업의 흐름을 형성할 수 있습니다 예를 들어 앱은 화면 스택에 템플릿을 추가할 수 있습니다. 자세한 내용은 템플릿 제한사항에서 자세한 내용을 확인하세요.
Screen
Screen는 앱에 표시되는 사용자 인터페이스를 관리하기 위해 앱이 구현하는 있습니다. Screen에는 수명 주기를 가지며, 앱에서 이러한 수명 주기 동안 화면이 표시되면 표시할 템플릿을 전송합니다. 인스턴스 Screen개도 푸시될 수 있음 Screen 스택에서 팝된 후 준수하여 템플릿 흐름 제한사항
CarAppService
CarAppService은(는) 추상 Service 클래스를 구현하고 내보내야 합니다. 앱의 CarAppService 상태: 호스트 연결을 신뢰할 수 있는지 검증하는 역할을 하며 createHostValidator 이후에 Session를 제공하여 각 연결에 대한 인스턴스를 onCreateSession
Session

Session는 추상 클래스로, 앱은 반드시 CarAppService.onCreateSession입니다. 자동차 화면에 정보를 표시하는 진입점 역할을 합니다. 그것은 수명 주기가 있어서 차량 화면에 표시된 앱의 현재 상태(예: 앱이 있습니다.

Session가 시작되는 경우(예: 앱이 처음 실행될 때 호스트는 초기 Screen: onCreateScreen 메서드를 사용하여 축소하도록 요청합니다.

자동차 앱 라이브러리 설치

Jetpack 라이브러리 보기 출시 페이지 앱에 라이브러리를 추가하는 방법에 관한 안내를 참조하세요.

앱의 매니페스트 파일 구성

자동차 앱을 만들려면 먼저 앱의 매니페스트 파일을 설치할 수 있습니다.

CarAppService 선언

호스트는 다음을 통해 앱에 연결합니다. CarAppService 구현 나 매니페스트에서 이 서비스를 선언하면 호스트가 이를 발견하고 연결할 수 있습니다. 해야 합니다.

앱 인텐트 필터의 <category> 요소에서 앱의 카테고리도 선언해야 합니다. 다음 목록을 참고하세요. 지원되는 앱 카테고리에서 이 요소에 적용됩니다.

다음 코드 스니펫은 다음 지점에 대한 자동차 앱 서비스를 선언하는 방법을 보여줍니다. 선택합니다.

<application>
    ...
   <service
       ...
        android:name=".MyCarAppService"
        android:exported="true">
      <intent-filter>
        <action android:name="androidx.car.app.CarAppService"/>
        <category android:name="androidx.car.app.category.POI"/>
      </intent-filter>
    </service>

    ...
<application>

지원되는 앱 카테고리

다음 카테고리 중 하나 이상을 추가하여 앱의 카테고리를 선언합니다. 값이 설명된 대로 CarAppService를 선언할 때 인텐트 필터의 값 이전 섹션에서 다음을 참조하세요.

  • androidx.car.app.category.NAVIGATION: 세부 경로 안내를 제공하는 앱입니다. 탐색 경로 자동차용 내비게이션 앱 빌드를 확인해 보세요. 에서 이 카테고리에 대한 추가 문서를 확인하세요.
  • androidx.car.app.category.POI: 관련성 높은 기능을 제공하는 앱입니다. 주차장, 충전소, 주유소 등 주유소 결제 자동차용 관심 장소 앱 빌드 이 카테고리에 대한 추가 문서를 참조하세요.
  • androidx.car.app.category.IOT: 사용자가 관련성 있는 정보를 얻을 수 있는 앱입니다. 작업을 실행할 수 있습니다. 결제 자동차용 사물 인터넷 앱 빌드 이 카테고리에 대한 추가 문서를 참조하세요.
를 통해 개인정보처리방침을 정의할 수 있습니다.

다음 경우에는 자동차용 Android 앱 품질을 참고하세요. 해야 합니다.

앱 이름 및 아이콘 지정

호스트가 시스템 UI에서 앱을 표시하는 데 사용할 수 있는 앱 이름과 아이콘을 지정해야 합니다.

앱을 나타내는 데 사용할 앱 이름과 아이콘을 지정할 수 있습니다. labelicon의 속성 CarAppService:

...
<service
   android:name=".MyCarAppService"
   android:exported="true"
   android:label="@string/my_app_name"
   android:icon="@drawable/my_app_icon">
   ...
</service>
...

라벨 또는 아이콘이 <service> 요소, 호스트 지정된 값으로 돌아가 <application> 요소

맞춤 테마 설정

자동차 앱의 맞춤 테마를 설정하려면 <meta-data> 요소 매니페스트 파일에 추가해야 합니다.

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

그런 다음 스타일 리소스를 선언하여 맞춤 자동차 앱 테마에 다음 속성을 설정합니다.

<resources>
  <style name="MyCarAppTheme">
    <item name="carColorPrimary">@layout/my_primary_car_color</item>
    <item name="carColorPrimaryDark">@layout/my_primary_dark_car_color</item>
    <item name="carColorSecondary">@layout/my_secondary_car_color</item>
    <item name="carColorSecondaryDark">@layout/my_secondary_dark_car_color</item>
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

자동차 앱 API 수준

자동차 앱 라이브러리는 자체 API 수준을 정의하므로 라이브러리 기능은 차량의 템플릿 호스트에서 지원합니다. 호스트에서 지원하는 가장 높은 자동차 앱 API 수준을 검색하려면 다음을 사용하세요. getCarAppApiLevel() 드림 메서드를 사용하여 축소하도록 요청합니다.

앱에서 지원하는 최소 자동차 앱 API 수준을 다음과 같이 선언합니다. AndroidManifest.xml 파일:

<manifest ...>
    <application ...>
        <meta-data
            android:name="androidx.car.app.minCarApiLevel"
            android:value="1"/>
    </application>
</manifest>

관련 문서를 참조하세요. RequiresCarApi 드림 이전 버전과의 호환성을 유지하고 기능을 사용하는 데 필요한 최소 API 수준입니다. 어떤 API에 대한 정의는 자동차 앱 라이브러리의 특정 기능을 사용하려면 필요한 경우 참조 문서: CarAppApiLevels

CarAppService 및 세션 만들기

앱은 CarAppService 클래스로 설정하고 이를 구현합니다. 이것의 onCreateSession 메서드 - Session를 반환합니다. 인스턴스를 만듭니다.

Kotlin

class HelloWorldService : CarAppService() {
    ...
    override fun onCreateSession(): Session {
        return HelloWorldSession()
    }
    ...
}

자바

public final class HelloWorldService extends CarAppService {
    ...
    @Override
    @NonNull
    public Session onCreateSession() {
        return new HelloWorldSession();
    }
    ...
}

Session 인스턴스는 다음을 담당합니다. Screen 인스턴스를 반환하여 실행할 때 다음과 같이 합니다.

Kotlin

class HelloWorldSession : Session() {
    ...
    override fun onCreateScreen(intent: Intent): Screen {
        return HelloWorldScreen(carContext)
    }
    ...
}

자바

public final class HelloWorldSession extends Session {
    ...
    @Override
    @NonNull
    public Screen onCreateScreen(@NonNull Intent intent) {
        return new HelloWorldScreen(getCarContext());
    }
    ...
}

자동차 앱이 일반적이지 않은 화면에서 시작해야 하는 시나리오를 처리하기 위해 앱의 홈 화면이나 랜딩 화면(예: 딥 링크 처리)에서 피처스토어를 사용하여 화면의 백 스택을 ScreenManager.push 드림 에서 돌아오기 전 onCreateScreen 미리 시드를 사용하면 사용자가 앱에서 표시하는 첫 화면에서 이전 화면으로 이동할 수 있습니다.

시작 화면 만들기

앱에서 표시하는 화면을 만들려면 Screen 클래스에 대해 알아보고 onGetTemplate 메서드를 호출하여 다음을 나타내는 Template 인스턴스 자동차 화면에 표시할 UI의 상태입니다.

다음 스니펫은 ScreenPaneTemplate 템플릿 간단한 'Hello world!' 문자열:

Kotlin

class HelloWorldScreen(carContext: CarContext) : Screen(carContext) {
    override fun onGetTemplate(): Template {
        val row = Row.Builder().setTitle("Hello world!").build()
        val pane = Pane.Builder().addRow(row).build()
        return PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build()
    }
}

자바

public class HelloWorldScreen extends Screen {
    @NonNull
    @Override
    public Template onGetTemplate() {
        Row row = new Row.Builder().setTitle("Hello world!").build();
        Pane pane = new Pane.Builder().addRow(row).build();
        return new PaneTemplate.Builder(pane)
            .setHeaderAction(Action.APP_ICON)
            .build();
    }
}

CarContext 클래스

CarContext 클래스는 ContextWrapper 서브클래스 SessionScreen 인스턴스 이를 통해 자동차 서비스에 ScreenManager: 화면 스택 일반적인 앱 관련 경우 AppManager 기능(예: 지도 그리기를 위한 Surface 객체에 액세스) 및 NavigationManager 세부 경로 안내 내비게이션 앱에서 내비게이션을 전달하는 데 사용됩니다. 메타데이터 및 기타 내비게이션 관련 이벤트를 사용해 지정할 수 있습니다

탐색 메뉴 액세스 템플릿을 내비게이션 앱에서 사용할 수 있는 라이브러리 기능의 전체 목록입니다.

CarContext는 기타 혜택도 제공합니다. 기능을 사용할 수 있습니다. 예를 들어, 구성을 사용하여 드로어블 리소스를 자동차 화면에서 인텐트를 사용하여 자동차에서 앱을 시작 앱에서 어두운 테마로 지도를 표시해야 하는지 신호를 보냅니다.

화면 내비게이션 구현

앱은 종종 다양한 화면을 표시하고, 각 화면은 사용자가 상호작용할 때 탐색할 수 있는 다양한 템플릿 인터페이스입니다.

ScreenManager 클래스는 자동으로 팝업될 수 있는 화면을 푸시하는 데 사용할 수 있는 화면 스택 사용자가 자동차 화면에서 뒤로 버튼을 선택하거나 하드웨어를 뒤로 사용할 때 일부 자동차에서 사용할 수 있습니다.

다음 스니펫은 메시지 템플릿에 뒤로 작업을 추가하는 방법을 사용자가 선택하면 새 화면을 푸시하는 작업이 포함됩니다.

Kotlin

val template = MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener { screenManager.push(NextScreen(carContext)) }
            .build())
    .build()

자바

MessageTemplate template = new MessageTemplate.Builder("Hello world!")
    .setHeaderAction(Action.BACK)
    .addAction(
        new Action.Builder()
            .setTitle("Next screen")
            .setOnClickListener(
                () -> getScreenManager().push(new NextScreen(getCarContext())))
            .build())
    .build();

Action.BACK 객체는 ScreenManager.pop을 자동으로 호출하는 표준 Action입니다. 이 동작은 OnBackPressedDispatcher 드림 'kubectl get pod my-test-app' CarContext입니다.

운전 중에 앱을 안전하게 사용할 수 있도록 화면 스택에는 최대 볼 수 있습니다. 템플릿 제한사항을 참고하세요. 섹션을 참조하세요.

템플릿 콘텐츠 새로고침

앱에서 ScreenScreen.invalidate 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다. 이후 호스트가 앱의 Screen.onGetTemplate 드림 메서드를 사용하여 새 콘텐츠가 있는 템플릿을 검색합니다.

Screen를 새로고침하면 업데이트할 수 있는 템플릿의 특정 콘텐츠를 이해하는 것이 중요합니다. 호스트가 템플릿 할당량에 새 템플릿을 포함하지 않습니다. 자세한 내용은 템플릿 제한사항 섹션을 참고하세요.

화면을 구성하는 것이 좋습니다. ScreenonGetTemplate 구현을 통해 반환되는 템플릿입니다.

지도 그리기

다음 템플릿을 사용하는 내비게이션 및 관심 장소 (POI) 앱은 Surface에 액세스하여 지도를 그립니다.

템플릿 템플릿 권한 카테고리 안내
NavigationTemplate androidx.car.app.NAVIGATION_TEMPLATES 탐색
MapWithContentTemplate androidx.car.app.NAVIGATION_TEMPLATES 또는
androidx.car.app.MAP_TEMPLATES
내비게이션, 관심 장소
MapTemplate (지원 중단됨) androidx.car.app.NAVIGATION_TEMPLATES 탐색
PlaceListNavigationTemplate (지원 중단됨) androidx.car.app.NAVIGATION_TEMPLATES 탐색
RoutePreviewNavigationTemplate (지원 중단됨) androidx.car.app.NAVIGATION_TEMPLATES 탐색

노출 영역 권한 선언

앱에서 사용 중인 템플릿에 필요한 권한 외에도 앱은 androidx.car.app.ACCESS_SURFACE 권한을 AndroidManifest.xml 파일을 사용하여 노출 영역에 액세스할 수 있습니다.

<manifest ...>
  ...
  <uses-permission android:name="androidx.car.app.ACCESS_SURFACE" />
  ...
</manifest>

노출 영역 액세스

호스트가 제공하는 Surface에 액세스하려면 다음을 구현해야 합니다. SurfaceCallbackAppManager에 자동차 서비스 현재 SurfaceSurfaceCallback SurfaceContainer 매개변수에 onSurfaceAvailable()onSurfaceDestroyed() 콜백

Kotlin

carContext.getCarService(AppManager::class.java).setSurfaceCallback(surfaceCallback)

자바

carContext.getCarService(AppManager.class).setSurfaceCallback(surfaceCallback);

표면에서 보이는 영역 이해하기

호스트는 지도 위에 여러 템플릿의 사용자 인터페이스 요소를 그릴 수 있습니다. 호스트는 모든 광섬유 케이블에서 사용자에게 완전히 보이는 SurfaceCallback.onVisibleAreaChanged 드림 메서드를 사용하여 축소하도록 요청합니다. 변경 횟수를 최소화하기 위해 호스트는 현재 템플릿에 따라 항상 표시되는 가장 작은 직사각형을 사용하여 SurfaceCallback.onStableAreaChanged 메서드도 호출합니다.

예를 들어 내비게이션 앱에서 NavigationTemplate 드림 상단에 작업 표시줄이 있는 경우 작업 표시줄을 숨기고 더 많은 광고를 게재하기 위해 한동안 화면과 상호작용하지 않을 때 공간을 확보해야 합니다. 이 경우에는 onStableAreaChanged의 콜백이 있으며 동일한 직사각형으로 onVisibleAreaChanged를 배치합니다. 작업 표시줄을 숨기면 onVisibleAreaChanged만 더 큰 영역으로 호출됩니다. 사용자가 화면과 상호작용하는 경우 다시 onVisibleAreaChanged만 첫 번째 직사각형입니다.

어두운 테마 지원

앱은 Surface 인스턴스에 지도를 적절한 어둡게로 다시 그려야 합니다. 호스트가 이를 보증한다고 판단하는 경우 자동차용 Android 앱 품질

어두운 지도를 그려야 하는지 판단하려면 CarContext.isDarkMode 메서드를 사용하면 됩니다. 어두운 테마 상태가 변경될 때마다 Session.onCarConfigurationChanged

사용자가 지도와 상호작용할 수 있도록 지원

다음 템플릿을 사용하면 사용자가 상호작용할 수 있도록 지원을 추가할 수 있습니다. 사용자가 그린 지도를 통해 지도의 다른 부분을 볼 수 있도록 하는 등 확대/축소 및 화면 이동이 가능합니다.

템플릿 자동차 앱 API 수준 이후 지원되는 상호작용
NavigationTemplate 2
PlaceListNavigationTemplate (지원 중단됨) 4
RoutePreviewNavigationTemplate (지원 중단됨) 4
MapTemplate (지원 중단됨) 5 (템플릿 소개)
MapWithContentTemplate 7 (템플릿 소개)

상호작용 콜백 구현

SurfaceCallback 인터페이스 에는 빌드된 지도에 상호작용을 추가하기 위해 구현할 수 있는 여러 콜백 메서드가 있습니다. 이전 섹션의 템플릿으로 사용할 수 있습니다.

상호작용 SurfaceCallback 메서드 자동차 앱 API 수준 이후 지원됨
onClick 5
손가락 모으기(확대/축소) onScale 2
원터치 드래그 onScroll 2
원터치 플링 onFling 2
두 번 탭 onScale (템플릿 호스트에 의해 결정되는 배율 사용) 2
화면 이동 모드에서 로터리 이동 onScroll (템플릿 호스트에서 결정하는 거리 계수 사용) 2

지도 작업 스트립 추가

이러한 템플릿에는 다음과 같은 지도 관련 작업을 위한 지도 작업 스트립을 포함할 수 있습니다. 확대/축소, 중심 재설정, 나침반 표시 등 다양한 작업을 수행할 수 있습니다. 선택할 수 있습니다. 지도 작업 스트립은 아이콘 전용 버튼을 최대 4개까지 포함할 수 있습니다. 새로고침이 가능합니다 유휴 상태 시 숨겨짐 활성 상태로 다시 표시됩니다

지도 상호작용 콜백을 수신하려면 다음 단계를 따르세요. 반드시 지도 작업 스트립에 Action.PAN 버튼을 추가해야 합니다. 사용자가 화면 이동 버튼을 누르면 호스트가 화면 이동 모드로 전환됩니다(다음 설명 참고). 섹션으로 이동합니다.

앱이 지도 작업 스트립에서 Action.PAN 버튼을 생략하면 SurfaceCallback 메서드로부터 사용자 입력을 수신하지 않게 되고 호스트는 이전에 활성화된 화면 이동 모드를 종료합니다.

터치스크린에는 화면 이동 버튼이 표시되지 않습니다.

화면 이동 모드 이해하기

화면 이동 모드에서는 템플릿 호스트가 터치 입력을 사용하지 않는 기기(예: 로터리 컨트롤러, 터치패드)의 사용자 입력을 적절한 SurfaceCallback 메서드로 변환합니다. 사용자 작업에 관한 응답으로 NavigationTemplate.BuildersetPanModeListener 메서드를 사용하여 화면 이동 모드에 진입하거나 화면 이동 모드를 종료합니다. 사용자가 화면 이동 모드에 있는 동안 호스트는 템플릿에서 다른 UI 구성요소를 숨길 수 있습니다.

사용자와 상호작용

앱은 모바일 앱과 유사한 패턴을 사용하여 사용자와 상호작용할 수 있습니다.

사용자 입력 처리

앱은 리스너를 지원하는 모델에 적절한 리스너를 전달하여 사용자 입력에 응답할 수 있습니다. 다음 스니펫은 Action 모델은 OnClickListener 앱의 코드에 정의된 메서드로 콜백합니다.

Kotlin

val action = Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(::onClickNavigate)
    .build()

자바

Action action = new Action.Builder()
    .setTitle("Navigate")
    .setOnClickListener(this::onClickNavigate)
    .build();

그러면 onClickNavigate 메서드가 기본 내비게이션 자동차 앱 를 사용하여 CarContext.startCarApp 메서드를 사용하여 축소하도록 요청합니다.

Kotlin

private fun onClickNavigate() {
    val intent = Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address))
    carContext.startCarApp(intent)
}

자바

private void onClickNavigate() {
    Intent intent = new Intent(CarContext.ACTION_NAVIGATE, Uri.parse("geo:0,0?q=" + address));
    getCarContext().startCarApp(intent);
}

ACTION_NAVIGATE 인텐트에 관한 내용은 인텐트로 자동차 앱 시작을 참고하세요. 섹션으로 이동합니다.

사용자가 휴대기기에서 상호작용을 계속하도록 안내해야 하는 일부 작업은 자동차가 주차된 때만 허용됩니다. 이 ParkedOnlyOnClickListener 드림 구현할 수 있습니다 자동차가 주차되지 않은 경우 호스트는 이 경우 허용되지 않는 작업임을 사용자에게 알립니다. 차량이 코드가 정상적으로 실행됩니다. 다음 스니펫은 ParkedOnlyOnClickListener 사용 모바일 기기에서 설정 화면을 열려면 다음 단계를 따르세요.

Kotlin

val row = Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(::openSettingsOnPhone))
    .build()

자바

Row row = new Row.Builder()
    .setTitle("Open Settings")
    .setOnClickListener(ParkedOnlyOnClickListener.create(this::openSettingsOnPhone))
    .build();

알림 표시

휴대기기로 전송된 알림은 다음과 같은 경우에만 차량 화면에 표시됩니다. PersistentVolumeClaim에 CarAppExtender 콘텐츠 제목, 텍스트, 아이콘, 작업 등 일부 알림 속성은 CarAppExtender에서 설정할 수 있어 알림의 속성을 재정의합니다. 자동차 화면에 표시될 때

다음 스니펫은 휴대기기에 표시된 것과 다른 제목을 표시하는 자동차 화면으로 알림을 전송하는 방법을 보여 줍니다.

Kotlin

val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build()

자바

Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
    .setContentTitle(titleOnThePhone)
    .extend(
        new CarAppExtender.Builder()
            .setContentTitle(titleOnTheCar)
            ...
            .build())
    .build();

알림은 다음과 같은 사용자 인터페이스 부분에 영향을 줄 수 있습니다.

  • 헤드업 알림(HUN)은 사용자에게 표시될 수 있습니다.
  • 알림 센터의 항목은 추가될 수 있고 선택적으로 배지가 레일에 표시됩니다.
  • 내비게이션 앱의 경우 알림이 레일 위젯에 다음과 같이 표시될 수 있습니다. 설명 세부 경로 안내 알림.
를 통해 개인정보처리방침을 정의할 수 있습니다.

앱의 알림을 구성하여 각 알림의 우선순위를 사용하여 이러한 사용자 인터페이스 요소를 를 CarAppExtender 드림 문서를 참조하세요.

만약 NotificationCompat.Builder.setOnlyAlertOnce 드림 값이 true로 호출되면 우선순위가 높은 알림은 다음과 같이 표시됩니다. HUN은 한 번만 사용할 수 있습니다.

자동차 앱의 알림을 디자인하는 방법에 관한 자세한 내용은 다음을 참고하세요. 운전을 위한 Google 디자인 가이드 알림:

토스트 메시지 표시

앱은 다음을 사용하여 토스트 메시지를 표시할 수 있습니다. CarToast는 다음 스니펫에 나와 있습니다.

Kotlin

CarToast.makeText(carContext, "Hello!", CarToast.LENGTH_SHORT).show()

자바

CarToast.makeText(getCarContext(), "Hello!", CarToast.LENGTH_SHORT).show();

권한 요청

앱에서 제한된 데이터 또는 작업에 액세스해야 하는 경우(예: 위치—Android의 표준 규칙 권한 적용됩니다. 권한을 요청하려면 CarContext.requestPermissions() 메서드를 사용하면 됩니다.

Cloud Functions의 이점은 CarContext.requestPermissions()표준 Android API는 자체 Activity를 실행할 필요가 없으므로 권한 대화상자를 만듭니다. 또한 동일한 코드를 Android Auto 및 Android Automotive OS를 만들 필요 없이 플랫폼에 종속된 플로우가 있습니다.

Android Auto의 권한 대화상자 스타일 지정

Android Auto에서는 사용자의 권한 대화상자가 휴대전화에 표시됩니다. 기본적으로 대화상자 뒤에 배경은 없습니다. 사용자 지정 배경에 자동차 앱 테마를 선언하려면 AndroidManifest.xml 파일을 만들고 carPermissionActivityLayout 속성을 설정합니다. 설정할 수 있습니다.

<meta-data
    android:name="androidx.car.app.theme"
    android:resource="@style/MyCarAppTheme />

그런 다음 자동차 앱 테마의 carPermissionActivityLayout 속성을 설정합니다.

<resources>
  <style name="MyCarAppTheme">
    <item name="carPermissionActivityLayout">@layout/my_custom_background</item>
  </style>
</resources>

인텐트로 자동차 앱 시작

다음과 같이 호출할 수 있습니다. CarContext.startCarApp 드림 메서드를 사용하여 다음 작업 중 하나를 수행합니다.

  • 다이얼러를 열어 전화를 겁니다.
  • 다음 항목이 있는 위치로 세부 경로 안내 내비게이션을 기본 내비게이션 자동차 앱.
  • 인텐트로 자체 앱을 시작합니다.

다음 예는 주차 예약 세부정보가 표시된 화면에서 앱을 여는 작업으로 알림을 만드는 방법을 보여 줍니다. 알림 인스턴스를 확장합니다. PendingIntent: 명시적 래핑 인텐트를 추가합니다.

Kotlin

val notification = notificationBuilder
    ...
    .extend(
        CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(ComponentName(context, MyNotificationReceiver::class.java)),
                    0))
            .build())

자바

Notification notification = notificationBuilder
    ...
    .extend(
        new CarAppExtender.Builder()
            .setContentIntent(
                PendingIntent.getBroadcast(
                    context,
                    ACTION_VIEW_PARKING_RESERVATION.hashCode(),
                    new Intent(ACTION_VIEW_PARKING_RESERVATION)
                        .setComponent(new ComponentName(context, MyNotificationReceiver.class)),
                    0))
            .build());

또한 앱은 BroadcastReceiver: 가 호출되어 사용자가 알림 인터페이스를 표시하고 CarContext.startCarApp 데이터 URI가 포함된 인텐트로 구성됩니다.

Kotlin

class MyNotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val intentAction = intent.action
        if (ACTION_VIEW_PARKING_RESERVATION == intentAction) {
            CarContext.startCarApp(
                intent,
                Intent(Intent.ACTION_VIEW)
                    .setComponent(ComponentName(context, MyCarAppService::class.java))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)))
        }
    }
}

자바

public class MyNotificationReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        String intentAction = intent.getAction();
        if (ACTION_VIEW_PARKING_RESERVATION.equals(intentAction)) {
            CarContext.startCarApp(
                intent,
                new Intent(Intent.ACTION_VIEW)
                    .setComponent(new ComponentName(context, MyCarAppService.class))
                    .setData(Uri.fromParts(MY_URI_SCHEME, MY_URI_HOST, intentAction)));
        }
    }
}

마지막으로 Session.onNewIntent 드림 앱의 메서드는 주차 예약 화면을 푸시하여 이 인텐트를 처리합니다. 를 호출합니다.

Kotlin

override fun onNewIntent(intent: Intent) {
    val screenManager = carContext.getCarService(ScreenManager::class.java)
    val uri = intent.data
    if (uri != null
        && MY_URI_SCHEME == uri.scheme
        && MY_URI_HOST == uri.schemeSpecificPart
        && ACTION_VIEW_PARKING_RESERVATION == uri.fragment
    ) {
        val top = screenManager.top
        if (top !is ParkingReservationScreen) {
            screenManager.push(ParkingReservationScreen(carContext))
        }
    }
}

자바

@Override
public void onNewIntent(@NonNull Intent intent) {
    ScreenManager screenManager = getCarContext().getCarService(ScreenManager.class);
    Uri uri = intent.getData();
    if (uri != null
        && MY_URI_SCHEME.equals(uri.getScheme())
        && MY_URI_HOST.equals(uri.getSchemeSpecificPart())
        && ACTION_VIEW_PARKING_RESERVATION.equals(uri.getFragment())
    ) {
        Screen top = screenManager.getTop();
        if (!(top instanceof ParkingReservationScreen)) {
            screenManager.push(new ParkingReservationScreen(getCarContext()));
        }
    }
}

자세한 내용은 알림 표시 섹션을 참고하세요. 자동차 앱의 알림을 처리하는 방법에 관한 정보

템플릿 제한사항

호스트가 특정 작업에 대해 표시할 템플릿 수를 최대로 제한합니다. 총 5개의 템플릿이 있으며, 이 중 마지막 템플릿은 다음 유형 중 하나여야 합니다.

이 제한은 템플릿 수에 적용되며 스택에 있는 인스턴스 Screen개 대상 예: 앱이 화면 A에 있는 동안 템플릿 2개를 전송하고 화면을 푸시하는 경우 B, 이제 템플릿을 세 개 더 보낼 수 있습니다. 또는 각 화면이 하나의 템플릿을 보내면 앱은 5개의 화면 인스턴스를 ScreenManager 스택.

이러한 제한에는 특수한 사례(템플릿 새로고침 및 뒤로 이동)가 있습니다. 재설정 작업을 수행합니다.

템플릿 새로고침

특정 콘텐츠 업데이트는 템플릿 제한에 포함되지 않습니다. 일반적으로 앱에서 푸시하는 새 템플릿을 기본 콘텐츠가 이전 템플릿과 동일하면 새 템플릿은 할당량에 포함됩니다 예를 들어 ListTemplate에서 행의 전환 상태를 업데이트해도 할당량에 포함되지 않습니다. 새로고침으로 간주할 수 있는 콘텐츠 업데이트 유형에 관한 자세한 내용은 개별 템플릿 문서를 참고하세요.

뒤로 작업

작업 내에서 하위 흐름을 사용 설정하기 위해 호스트는 앱이 ScreenManager 스택 및 업데이트의 Screen 앱에서 사용할 템플릿 수를 기준으로 남은 할당량 뒤로 가기 위함입니다.

예를 들어 앱이 화면 A에 있는 동안 템플릿 2개를 전송한 후 템플릿을 2개 더 전송하면 앱에는 남은 할당량이 하나 있습니다. 만약 그런 다음 앱이 화면 A로 다시 돌아오면 호스트는 할당량을 3으로 재설정합니다. 앱이 템플릿 두 개 뒤로 돌아갔습니다.

참고로, 화면으로 다시 돌아올 때 앱은 해당 화면에서 마지막으로 전송된 것과 동일한 유형일 수 있습니다. 기타 메시지 보내기 템플릿 유형으로 인해 오류가 발생합니다. 그러나 뒤로 작업 시 유형이 동일하게 유지되는 한 앱은 할당량에 영향을 주지 않고 템플릿의 콘텐츠를 자유롭게 수정할 수 있습니다.

작업 재설정

특정 템플릿에는 작업의 끝을 나타내는 특수한 의미 체계가 있습니다. 대상 예를 들어 NavigationTemplate 드림 화면에 유지되고 새로 고침되는 뷰로 세부 경로 안내도 제공합니다. 이러한 트래픽 중 하나에 도달하면 호스트는 템플릿 할당량을 재설정하여 템플릿을 마치 새 작업의 첫 번째 단계입니다 이렇게 하면 앱이 새 작업을 시작할 수 있습니다. 호스트에서 재설정을 트리거하는 템플릿은 개별 템플릿 문서를 참고하세요.

호스트가 알림 작업에서 앱을 시작하기 위한 인텐트를 수신하거나 런처에서 할당량도 재설정됩니다. 이 메커니즘을 통해 앱은 알림에서 새로운 작업 흐름을 시작할 수 있으며 이는 앱이 포그라운드에 있습니다.

자세한 내용은 알림 표시 섹션을 참고하세요. 자동차 화면에 앱의 알림을 표시하는 방법을 알아보세요. 자세한 내용은 인텐트로 자동차 앱 시작 섹션에서 방법 알아보기 알림 작업에서 앱을 시작할 수 있습니다.

연결 API

앱이 Android Auto 또는 Android에서 실행되는지 확인할 수 있습니다. Automotive OS는 CarConnection API 대상 런타임 시 연결 정보를 검색할 수 있습니다.

예를 들어 자동차 앱의 Session에서 CarConnection를 초기화하고 LiveData개 업데이트 구독:

Kotlin

CarConnection(carContext).type.observe(this, ::onConnectionStateUpdated)

자바

new CarConnection(getCarContext()).getType().observe(this, this::onConnectionStateUpdated);

그런 다음 관찰자에서 연결 상태 변경에 반응할 수 있습니다.

Kotlin

fun onConnectionStateUpdated(connectionState: Int) {
  val message = when(connectionState) {
    CarConnection.CONNECTION_TYPE_NOT_CONNECTED -> "Not connected to a head unit"
    CarConnection.CONNECTION_TYPE_NATIVE -> "Connected to Android Automotive OS"
    CarConnection.CONNECTION_TYPE_PROJECTION -> "Connected to Android Auto"
    else -> "Unknown car connection type"
  }
  CarToast.makeText(carContext, message, CarToast.LENGTH_SHORT).show()
}

자바

private void onConnectionStateUpdated(int connectionState) {
  String message;
  switch(connectionState) {
    case CarConnection.CONNECTION_TYPE_NOT_CONNECTED:
      message = "Not connected to a head unit";
      break;
    case CarConnection.CONNECTION_TYPE_NATIVE:
      message = "Connected to Android Automotive OS";
      break;
    case CarConnection.CONNECTION_TYPE_PROJECTION:
      message = "Connected to Android Auto";
      break;
    default:
      message = "Unknown car connection type";
      break;
  }
  CarToast.makeText(getCarContext(), message, CarToast.LENGTH_SHORT).show();
}

제약조건 API

차량에 따라 허용되는 수의 다음 사용자에게 표시될 인스턴스 Item개 생성할 수 있습니다. 사용 ConstraintManager 드림 를 사용하여 런타임에 콘텐츠 제한을 확인하고 적절한 항목 수를 설정하세요. 사용할 수 있습니다.

먼저 CarContext에서 ConstraintManager를 가져옵니다.

Kotlin

val manager = carContext.getCarService(ConstraintManager::class.java)

자바

ConstraintManager manager = getCarContext().getCarService(ConstraintManager.class);

그런 다음 가져온 ConstraintManager 객체에 관한 콘텐츠 한도 예를 들어 그리드, 호출 getContentLimit 드림 다음 코드로 교체합니다. CONTENT_LIMIT_TYPE_GRID:

Kotlin

val gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID)

자바

int gridItemLimit = manager.getContentLimit(ConstraintManager.CONTENT_LIMIT_TYPE_GRID);

로그인 흐름 추가

앱에서 사용자에게 로그인 환경을 제공하는 경우 다음과 같은 템플릿을 사용할 수 있습니다. SignInTemplateLongMessageTemplate 자동차 앱 API 수준 2 이상에서 자동차 헤드 유닛입니다.

SignInTemplate를 만들려면 SignInMethod를 정의합니다. 자동차 앱 라이브러리는 현재 다음과 같은 로그인 방법을 지원합니다.

  • InputSignInMethod 드림 (사용자 이름/비밀번호 로그인)
  • PinSignInMethod 드림 사용자가 휴대전화에서 계정을 연결하는 PIN 로그인의 경우 헤드 단위에 표시된 PIN을 사용합니다.
  • ProviderSignInMethod 드림 : Google 로그인원탭입니다.
  • QRCodeSignInMethod 드림 사용자가 QR 코드를 스캔하여 로그인을 완료하는 QR 코드 로그인 스마트폰 이 기능은 자동차 API 수준 4 이상에서 사용할 수 있습니다.

예를 들어, 사용자 비밀번호를 수집하는 템플릿을 구현하려면 사용자 입력을 처리하고 확인하는 InputCallback을 생성하여 시작합니다.

Kotlin

val callback = object : InputCallback {
    override fun onInputSubmitted(text: String) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    override fun onInputTextChanged(text: String) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
}

자바

InputCallback callback = new InputCallback() {
    @Override
    public void onInputSubmitted(@NonNull String text) {
        // You will receive this callback when the user presses Enter on the keyboard.
    }

    @Override
    public void onInputTextChanged(@NonNull String text) {
        // You will receive this callback as the user is typing. The update
        // frequency is determined by the host.
    }
};

InputCallbackInputSignInMethod Builder에 필요합니다.

Kotlin

val passwordInput = InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build()

자바

InputSignInMethod passwordInput = new InputSignInMethod.Builder(callback)
    .setHint("Password")
    .setInputType(InputSignInMethod.INPUT_TYPE_PASSWORD)
    ...
    .build();

마지막으로 새로운 InputSignInMethod를 사용하여 SignInTemplate을 만듭니다.

Kotlin

SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build()

자바

new SignInTemplate.Builder(passwordInput)
    .setTitle("Sign in with username and password")
    .setInstructions("Enter your password")
    .setHeaderAction(Action.BACK)
    ...
    .build();

AccountManager 사용

인증이 포함된 Android Automotive OS 앱은 다음과 같은 이유로 AccountManager를 사용해야 합니다.

  • 향상된 UX 및 용이한 계정 관리: 사용자가 모든 것을 쉽게 관리할 수 있습니다. 시스템 설정의 계정 메뉴에서 로그인 등 자신의 계정 있습니다.
  • "게스트" 사용 환경: 자동차는 공유 기기이므로 OEM은 계정을 추가할 수 없는 차량 내 사용자 환경입니다.

텍스트 문자열 변형 추가

자동차 화면 크기에 따라 표시되는 텍스트양이 다를 수 있습니다. 자동차 앱 API 수준 2 이상에서는 화면에 가장 적합하도록 텍스트 문자열의 변형을 여러 가지로 지정할 수 있습니다. 텍스트 변형이 허용되는 위치를 확인하려면 CarText를 사용하는 템플릿 및 구성요소를 찾아야 합니다.

CarText에 텍스트 문자열 변형을 추가할 수 있습니다. CarText.Builder.addVariant() 메서드를 사용하여 축소하도록 요청합니다.

Kotlin

val itemTitle = CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build()

자바

CarText itemTitle = new CarText.Builder("This is a very long string")
    .addVariant("Shorter string")
    ...
    .build();

그런 다음 이 CarText를 예를 들어 요소의 기본 텍스트로 사용할 수 있습니다. GridItem

Kotlin

GridItem.Builder()
    .addTitle(itemTitle)
    ...
    .build()

자바

new GridItem.Builder()
    .addTitle(itemTitle)
    ...
    build();

선호도가 가장 높은 것부터 순서대로 문자열 추가(예: 가장 긴 것부터 가장 긴 것 순으로) 가장 짧은 방법입니다. 호스트는 충분한 공간을 확보할 수 있습니다.

행에 인라인 CarIcons 추가

텍스트와 함께 아이콘을 추가하여 앱의 시각적 매력을 보강할 수 있습니다. CarIconSpan 다음 문서를 참조하세요. CarIconSpan.create 드림 를 참조하세요. 자세한 내용은 Spantastic 스팬으로 텍스트 스타일 지정을 참조하세요.

Kotlin

  
val rating = SpannableString("Rating: 4.5 stars")
rating.setSpan(
    CarIconSpan.create(
        // Create a CarIcon with an image of four and a half stars
        CarIcon.Builder(...).build(),
        // Align the CarIcon to the baseline of the text
        CarIconSpan.ALIGN_BASELINE
    ),
    // The start index of the span (index of the character '4')
    8,
    // The end index of the span (index of the last 's' in "stars")
    16,
    Spanned.SPAN_INCLUSIVE_INCLUSIVE
)

val row = Row.Builder()
    ...
    .addText(rating)
    .build()
  
  

자바

  
SpannableString rating = new SpannableString("Rating: 4.5 stars");
rating.setSpan(
        CarIconSpan.create(
                // Create a CarIcon with an image of four and a half stars
                new CarIcon.Builder(...).build(),
                // Align the CarIcon to the baseline of the text
                CarIconSpan.ALIGN_BASELINE
        ),
        // The start index of the span (index of the character '4')
        8,
        // The end index of the span (index of the last 's' in "stars")
        16,
        Spanned.SPAN_INCLUSIVE_INCLUSIVE
);
Row row = new Row.Builder()
        ...
        .addText(rating)
        .build();
  
  

자동차 하드웨어 API

자동차 앱 API 수준 3부터 자동차 앱 라이브러리에는 차량 속성 및 센서에 액세스하는 데 사용할 수 있습니다.

요구사항

Android Auto에서 API를 사용하려면 먼저 Android용 build.gradle 파일에 androidx.car.app:app-projected 추가 자동 모듈 Android Automotive OS의 경우 다음의 종속 항목을 추가합니다. Android용 build.gradle 파일에 androidx.car.app:app-automotive 추가 Automotive OS 모듈입니다.

또한 AndroidManifest.xml 파일에서 다음을 실행해야 합니다. 필요한 관련 권한을 선언합니다. 사용할 자동차 데이터를 요청할 수 있습니다. 이러한 권한은 부여합니다. 이 Android Auto와 Android Automotive OS에서 동일한 코드를 사용하는 것이 아니라 만들 필요가 없다는 것입니다 하지만 필요한 권한은 다릅니다.

자동차 정보

이 표에서는 CarInfo API 및 다음 권한을 요청합니다.

메서드 속성 Android Auto 권한 Android Automotive OS 권한 자동차 앱 API 수준 이후 지원됨
fetchModel 제조업체, 모델, 연도 android.car.permission.CAR_INFO 3
fetchEnergyProfile 전기자동차 커넥터 유형, 연료 유형 com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_INFO 3
fetchExteriorDimensions

<ph type="x-smartling-placeholder"></ph> 이 데이터는 일부 Android Automotive OS 차량에서만 사용할 수 있습니다. API 30 이상 실행 를 통해 개인정보처리방침을 정의할 수 있습니다.

외부 크기 해당 사항 없음 android.car.permission.CAR_INFO 7
addTollListener
removeTollListener
통행료 카드 상태, 통행료 카드 유형 3
addEnergyLevelListener
removeEnergyLevelListener
배터리 잔량, 연료 잔량, 연료 잔량 부족, 남은 주행 가능 거리 com.google.android.gms.permission.CAR_FUEL android.car.permission.CAR_ENERGY,
android.car.permission.CAR_ENERGY_PORTS,
android.car.permission.READ_CAR_DISPLAY_UNITS
3
addSpeedListener
removeSpeedListener
원시 속도, 디스플레이 속도 (자동차의 계기판 디스플레이에 표시됨) com.google.android.gms.permission.CAR_SPEED android.car.permission.CAR_SPEED,
<ph type="x-smartling-placeholder">android.car.permission.READ_CAR_DISPLAY_UNITS</ph>
3
addMileageListener
removeMileageListener
주행 거리계 com.google.android.gms.permission.CAR_MILEAGE 이 데이터는 Android Automotive OS에서 Play 스토어에서 설치한 앱에 제공되지 않습니다. 3

예를 들어 나머지 범위를 가져오려면 CarInfo 객체 다음 OnCarDataAvailableListener를 만들고 등록합니다.

Kotlin

val carInfo = carContext.getCarService(CarHardwareManager::class.java).carInfo

val listener = OnCarDataAvailableListener<EnergyLevel> { data ->
    if (data.rangeRemainingMeters.status == CarValue.STATUS_SUCCESS) {
      val rangeRemaining = data.rangeRemainingMeters.value
    } else {
      // Handle error
    }
  }

carInfo.addEnergyLevelListener(carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener)

자바

CarInfo carInfo = getCarContext().getCarService(CarHardwareManager.class).getCarInfo();

OnCarDataAvailableListener<EnergyLevel> listener = (data) -> {
  if(data.getRangeRemainingMeters().getStatus() == CarValue.STATUS_SUCCESS) {
    float rangeRemaining = data.getRangeRemainingMeters().getValue();
  } else {
    // Handle error
  }
};

carInfo.addEnergyLevelListener(getCarContext().getMainExecutor(), listener);

// Unregister the listener when you no longer need updates
carInfo.removeEnergyLevelListener(listener);

자동차의 데이터를 항상 사용할 수 있다고 가정하지 마세요. 오류가 발생하면 상태: 요청한 데이터가 가져올 수 없습니다. 자세한 내용은 참조 문서: 전체 CarInfo 클래스 정의

자동차 센서

CarSensors 클래스 를 통해 차량의 가속도계, 자이로스코프, 나침반 및 위치 데이터 이러한 값의 사용 가능 여부는 OEM입니다. 가속도계, 자이로스코프 및 나침반의 데이터 형식은 동일한 인코더-디코더 SensorManager API 예를 들어 차량 방향을 확인합니다.

Kotlin

val carSensors = carContext.getCarService(CarHardwareManager::class.java).carSensors

val listener = OnCarDataAvailableListener<Compass> { data ->
    if (data.orientations.status == CarValue.STATUS_SUCCESS) {
      val orientation = data.orientations.value
    } else {
      // Data not available, handle error
    }
  }

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, carContext.mainExecutor, listener)

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener)

자바

CarSensors carSensors = getCarContext().getCarService(CarHardwareManager.class).getCarSensors();

OnCarDataAvailableListener<Compass> listener = (data) -> {
  if (data.getOrientations().getStatus() == CarValue.STATUS_SUCCESS) {
    List<Float> orientations = data.getOrientations().getValue();
  } else {
    // Data not available, handle error
  }
};

carSensors.addCompassListener(CarSensors.UPDATE_RATE_NORMAL, getCarContext().getMainExecutor(),
    listener);

// Unregister the listener when you no longer need updates
carSensors.removeCompassListener(listener);

자동차에서 위치 데이터에 액세스하려면 android.permission.ACCESS_FINE_LOCATION 권한

테스트

Android Auto에서 테스트할 때 센서 데이터를 시뮬레이션하려면 다음을 참고하세요. 센서센서 구성 섹션에 데스크톱 헤드 단위 가이드 Android에서 테스트할 때 센서 데이터를 시뮬레이션하기 위해 자세한 내용은 하드웨어 에뮬레이션 상태 섹션에 표시됩니다. Automotive OS 에뮬레이터 가이드

CarAppService, Session 및 Screen 수명 주기

SessionScreen 클래스는 LifecycleOwner 인터페이스 따라서 사용자가 앱, SessionScreen 객체와 상호작용 수명 주기 다음 다이어그램에 설명된 대로 콜백이 호출됩니다.

CarAppService 및 세션의 수명 주기

그림 1. Session 수명 주기

자세한 내용은 Session.getLifecycle 드림 메서드를 사용하여 축소하도록 요청합니다.

화면의 수명 주기

그림 2. Screen 수명 주기

자세한 내용은 Screen.getLifecycle 메서드를 사용하여 지도 가장자리에 패딩을 추가할 수 있습니다.

차량 마이크에서 녹음

앱의 CarAppServiceCarAudioRecord API 앱에 사용자의 자동차 마이크 액세스 권한을 부여할 수 있습니다. 사용자는 차량 마이크에 액세스할 수 있는 앱 권한이 있어야 합니다. 앱에서는 앱 내에서 사용자 입력을 처리합니다.

녹화 권한

오디오를 녹음하기 전에 먼저 오디오 녹음 파일에서 AndroidManifest.xml로 설정하고 사용자에게 부여하도록 요청합니다.

<manifest ...>
   ...
   <uses-permission android:name="android.permission.RECORD_AUDIO" />
   ...
</manifest>

런타임에 녹화 권한을 요청해야 합니다. 자세한 내용은 요청 권한 섹션을 참조하세요. 자동차 앱에서 권한을 요청할 수 있습니다.

오디오 녹음

사용자가 녹음 권한을 부여하면 오디오를 녹음하고 확인할 수 있습니다.

Kotlin

val carAudioRecord = CarAudioRecord.create(carContext)
        carAudioRecord.startRecording()

        val data = ByteArray(CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE)
        while(carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording()
 

자바

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        carAudioRecord.startRecording();

        byte[] data = new byte[CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE];
        while (carAudioRecord.read(data, 0, CarAudioRecord.AUDIO_CONTENT_BUFFER_SIZE) >= 0) {
            // Use data array
            // Potentially call carAudioRecord.stopRecording() if your processing finds end of speech
        }
        carAudioRecord.stopRecording();
 

오디오 포커스

자동차 마이크로 녹음할 때는 먼저 오디오를 확보합니다. 집중 진행 중인 미디어가 중지되었는지 확인합니다. 오디오 포커스를 잃어버린 경우 녹음을 중지합니다.

다음은 오디오 포커스를 획득하는 방법의 예입니다.

Kotlin

 
val carAudioRecord = CarAudioRecord.create(carContext)
        
        // Take audio focus so that user's media is not recorded
        val audioAttributes = AudioAttributes.Builder()
            .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
            // Use the most appropriate usage type for your use case
            .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
            .build()
        
        val audioFocusRequest =
            AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                .setAudioAttributes(audioAttributes)
                .setOnAudioFocusChangeListener { state: Int ->
                    if (state == AudioManager.AUDIOFOCUS_LOSS) {
                        // Stop recording if audio focus is lost
                        carAudioRecord.stopRecording()
                    }
                }
                .build()
        
        if (carContext.getSystemService(AudioManager::class.java)
                .requestAudioFocus(audioFocusRequest)
            != AudioManager.AUDIOFOCUS_REQUEST_GRANTED
        ) {
            // Don't record if the focus isn't granted
            return
        }
        
        carAudioRecord.startRecording()
        // Process the audio and abandon the AudioFocusRequest when done

자바

CarAudioRecord carAudioRecord = CarAudioRecord.create(getCarContext());
        // Take audio focus so that user's media is not recorded
        AudioAttributes audioAttributes =
                new AudioAttributes.Builder()
                        .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
                        // Use the most appropriate usage type for your use case
                        .setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE)
                        .build();

        AudioFocusRequest audioFocusRequest =
                new AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_EXCLUSIVE)
                        .setAudioAttributes(audioAttributes)
                        .setOnAudioFocusChangeListener(state -> {
                            if (state == AudioManager.AUDIOFOCUS_LOSS) {
                                // Stop recording if audio focus is lost
                                carAudioRecord.stopRecording();
                            }
                        })
                        .build();

        if (getCarContext().getSystemService(AudioManager.class).requestAudioFocus(audioFocusRequest)
                != AUDIOFOCUS_REQUEST_GRANTED) {
            // Don't record if the focus isn't granted
            return;
        }

        carAudioRecord.startRecording();
        // Process the audio and abandon the AudioFocusRequest when done
 

테스트 라이브러리

자동차용 Android 테스트 라이브러리는 클래스를 정의합니다. 예를 들어 SessionController 드림 호스트와의 연결을 시뮬레이션하고 올바른 포트가 선택되었는지 ScreenTemplate가 생성되고 반환합니다.

자세한 내용은 샘플 사용 예를 참조하세요.

자동차용 Android 앱 라이브러리 문제 신고

라이브러리에 문제가 있다면 Google Issue Tracker를 사용하여 신고하세요. 문제 템플릿에 요청된 모든 정보를 작성해야 합니다.

새 문제 만들기

새로운 문제를 신고하기 전에 해당 문제가 라이브러리 버전에 포함되어 있는지 확인하세요. 문제 목록에 보고될 수 있습니다. Tracker에서 문제의 별표를 클릭하여 문제를 구독하고 투표를 할 수 있습니다. 자세한 내용은 문제 구독을 참고하세요.