기술 세부정보

이 섹션에서는 제어 센터 참조 앱과 관련된 기술 세부정보를 제공합니다.

제어 센터는 번들로 묶이지 않은 권한 있는 시스템 서명 앱으로, 최소 SDK 버전 35 (Android V (API 수준 35))가 필요합니다. 이 앱은 System APIs를 사용하기 위해 system/priv-app에 설치됩니다. 미디어 정보를 읽으려면 앱이 플랫폼 서명되어야 합니다. 앱을 OTA (Over-the-Air)로 업데이트할 수 있습니다.

백그라운드 서비스

제어 센터 앱은 기능을 위해 백그라운드 서비스에 의존합니다. Control Center ServiceVendor ServiceController에 의해 사용자 수명 주기의 user-post-unlocked 상태에서 시작됩니다. 제어 센터는 항상 활성 상태여야 하며 백그라운드에서 통신해야 합니다. 앱은 사용자가 앱을 열 때 의존할 수 없습니다.

Control Center ServiceCommunication API를 사용하여 다른 점유자 영역의 자체 다른 인스턴스에 연결하고 통신합니다. 통합 가이드를 읽는 것은 각 사용자의 제어 센터 인스턴스가 연결을 설정하고 데이터를 주고받는 방법을 이해하는 데 필수적입니다.

공급업체 ServiceController에 의해 시작되는 Control Center Service를 보여주는 다이어그램
그림 5. Vendor ServiceController에서 시작된 제어 센터 서비스

커뮤니케이션

연결되면 Control Center Service는 정보를 전달하는 protobuf 객체와 통신합니다. protobuf를 다른 점유자 영역에 전달하려면 Communication APIs를 사용하여 protobufbyte array로 변환되고 payload object가 생성되며 PayloadCarOccupantConnectionManager#sendPayload를 통해 전송됩니다.

message ControlCenterPayload {
    required Type messageType = 1;
    // ...
    enum Type {
       MEDIA_STATUS = 0;
       MEDIA_COMMAND = 1;
       INPUT_LOCK_COMMAND = 2;
       INPUT_LOCK_SUCCESSFUL = 3;
       CANCEL_AUDIO_REQUEST = 4;
       MIRRORING_REQUEST_RECEIVER_DECISION = 5;
       MIRRORING_SESSION_ENDED = 6;
    }
}

private fun parsePayload(
    senderZone: OccupantZoneInfo,
    payload: Payload
) {
     val parsedPayload =
         ControlCenterPayload.parseFrom(payload.bytes)
             when (parsedPayload.messageType) {
                 ControlCenterPayload.Type.MEDIA_STATUS -> {
                     // logic here
                 }
             }
             //…
}

데이터

점유자 영역에 관한 정보는 OccupantZoneData 객체 형태로 제어 센터에 저장됩니다. 로컬 OccupantZoneData의 변경사항은 Comms API를 통해 다른 제어 센터 인스턴스로 전송됩니다.

수신된 Payload가 파싱되면 파싱된 데이터가 로컬 OccupantZoneStateRepository로 전달되고, 이 저장소는 변경사항을 뷰에 알립니다. 대부분의 데이터는 Kotlin flows on Android를 사용하여 클래스 간에 전달됩니다.

차량 스피커 오디오 요청 처리

운전자가 항상 승객이 차량 스피커를 통해 오디오를 재생하도록 요청을 받을 수 있도록 하기 위해 생성되면 운전자의 Control Center Service Primary ZoneMedia Audio RequestCallback를 등록합니다.

콜백은 호출을 알립니다 CarAudioManager#requestMediaAudioOnPrimaryZone. 운전자의 Control Center ServiceCarAudioManager#allowMediaAudioOnPrimaryZone(boolean)을 통해 수락하거나 거부할 수 있는 헤드업 알림 (HUN)을 만들어 요청을 처리합니다.

다른 화면으로 동영상 공동 시청

공동 시청은 CarActivityManagerTask Mirroring APIs로 인해 작동합니다. TaskMirroringManager는 먼저 CarActivityManager#getVisibleTasks에서 재생 중인 MediaSession 앱의 패키지를 검색한 다음 VirtualDisplay를 만들고 CarActivityManager#moveRootTaskToDisplay를 통해 표시되는 작업을 이 디스플레이로 이동합니다.

이렇게 하면 IBinder 토큰이 MirroredSurfaceView가 레이아웃에서 MirroredSurfaceView#mirrorSurface를 통해 작업을 표시하는 데 사용할 수 있는 반환됩니다. Communication API Payload 객체는 토큰을 다른 점유자 영역에 전달했습니다.

이러한 점유자 영역의 각 제어 센터 인스턴스는 Mirroring activity를 실행하고 이 토큰을 사용하여 MirroredSurfaceView를 채웁니다.

다른 화면에 작업을 표시하기 위한 미러링 토큰의 흐름
그림 6. 토큰 흐름 미러링

작업 미러링 API

제어 센터는 다음과 같은 작업 미러링 API를 사용합니다.

CarActivityManager#getVisibleTasks(int displayId)
<ActivityManager.RunningTaskInfo> 발신자 디스플레이에 호출됩니다.

CarActivityManager#moveRootTaskToDisplay(int virtualDisplayId)
선택한 표시되는 작업을 생성된 가상 디스플레이로 이동합니다.

CarActivityManager#createTaskMirroringToken(int taskId)
IBinder 토큰을 미러링하는 작업을 만들고 작업이 가상 디스플레이로 이동된 후에 호출해야 합니다.

MirroredSurfaceView#mirrorSurface(IBinder token)
토큰을 사용하여 |가상 디스플레이의 콘텐츠를 표시하는 맞춤 뷰 객체입니다.

제어 센터의 작업 미러링 제한사항

제어 센터는 MediaSession 앱의 작업 미러링만 지원합니다. 하지만 API는 모든 작업을 미러링할 수 있습니다. 가상 디스플레이는 발신자 디스플레이의 크기로 만들어집니다. 수신자의 디스플레이가 다른 해상도와 크기를 사용하는 경우 가상 디스플레이가 화면 중앙에 표시됩니다.

표면 표시 작업

제어 센터는 섀시 Theme.CarUi.NoToolbar를 반투명 창으로 확장합니다. 즉, 작업 위에 제어 센터가 열리면 작업이 CarActivityManager#getVisibleTasks에 반환되어 작업을 미러링할 수 있습니다.

미러링 정보 수신

제어 센터는 다른 앱에 미러링 세션을 알립니다. 업데이트를 수신하려면 앱이 Control Center Service에 바인딩하고 Control Center Service에서 Messages를 수신하고 처리하는 클라이언트로 Handler 클래스를 전송해야 합니다.

클라이언트 앱은 미러링된 앱의 패키지 이름을 수신하고 이러한 키를 사용하여 미러링된 앱을 호스팅하는 제어 센터의 활동에 intent URI를 실행할 수 있습니다.

  • _config_msg_mirroring_pkg_name_key_
  • _config_msg_mirroring_redirect_uri_key_

이러한 구성은 클라이언트 앱 리소스와 제어 센터 리소스에 있어야 합니다.

클라이언트 앱은 제어 센터에서 미러링 정보를 수신합니다.
그림 7. 제어 센터에서 미러링 정보 수신

제어 센터 디버그

Logger 클래스는 제어 센터 로그를 처리하며, 로그를 강제하도록 구성할 수 있습니다.

class Logger(cls: Class<*>) {

   companion object {
       private const val FORCE_LOGS = false
   }

   private val tag: String

   init {
       tag = cls.simpleName
   }

   fun v(message: String) {
       if (Log.isLoggable(tag, Log.VERBOSE) || FORCE_LOGS) {
           Log.v(tag, message)
       }
   }
...

시스템 앱 및 업데이트 가능성

제어 센터는 서명 전용 권한을 사용하므로 시스템 앱이고 플랫폼 서명되어 있기 때문에 제어 센터는 기기에 사전 설치되어야 하며 Car Media App과 마찬가지로 OTA로만 업데이트할 수 있습니다.

소스에서 제어 센터 빌드

제어 센터 소스 코드를 가져오려면 번들로 묶이지 않은 앱 통합을 참고하세요.

다중 디스플레이를 통한 사용자 개인 정보 보호

제어 센터를 사용하면 모든 차량 승객이 모든 디스플레이에서 미디어 정보를 볼 수 있습니다. Google은 사용자에게 알리기 위해 차단되지 않는 개인정보처리방침을 삽입하는 것이 좋습니다. Google은 디스플레이에 로그인할 때 시스템 수준에서 이 작업을 실행하는 것이 좋습니다.