詳細な技術情報

このセクションでは、コントロール センターのリファレンス アプリに固有の技術的な詳細について説明します。

コントロール センターは、バンドルされていない特権システム署名アプリであり、最小 SDK バージョン 35(Android V(API レベル 35))が必要です。アプリは System APIs を使用するために system/priv-app にインストールされます。メディア情報を読み取るには、アプリがプラットフォーム署名されている必要があります。アプリは無線(OTA)で更新できます。

バックグラウンド サービス

コントロール センター アプリは、その機能のためにバックグラウンド サービスに依存しています。Control Center Service は、Vendor ServiceController によってユーザー ライフサイクルの user-post-unlocked 状態で開始されます。コントロール センターは常にアクティブで、バックグラウンドで通信している必要があります。アプリは、ユーザーがアプリを開くことを前提にすることはできません。

Control Center Service は、Communication API を使用して、他のテナント ゾーンにある自身の他のインスタンスに接続して通信します。各ユーザーの Control Center インスタンスが接続を確立し、データを送受信する方法を理解するには、統合ガイドを読むことが不可欠です。

ベンダーの ServiceController によって開始される Control Center Service を示す図。
図 5. ベンダーの ServiceController によって開始された Control Center Service。

コミュニケーション

接続されると、Control Center Service は情報を伝達する protobuf オブジェクトと通信します。Communication APIs を使用して protobuf を別の乗員ゾーンに渡すために、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 Service は、CarAudioManager#allowMediaAudioOnPrimaryZone(boolean) を通じて承認または拒否できるヘッドアップ通知(HUN)を作成してリクエストを処理します。

他の画面で動画を同時視聴する

同時視聴は、CarActivityManagerTask Mirroring APIs によって機能します。TaskMirroringManager は、まず CarActivityManager#getVisibleTasks で再生中の MediaSession アプリのパッケージを検索し、VirtualDisplay を作成して、CarActivityManager#moveRootTaskToDisplay を介して表示中のタスクをこのディスプレイに移動します。

これにより、MirroredSurfaceView がレイアウトで使用して MirroredSurfaceView#mirrorSurface を介してタスクを表示できる IBinder トークンが返されます。Communication API Payload オブジェクトは、トークンを他の占有者ゾーンに渡しました。

これらの乗員ゾーンの各 Control Center インスタンスは 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 クラスは Control Center ログを処理します。このログは強制ログとして設定できます。

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)
       }
   }
...

システムアプリと更新可能性

コントロール センターは、署名のみの権限を使用しているため、システムアプリであり、プラットフォーム署名されています。そのため、コントロール センターはデバイスにプリインストールする必要があり、カー メディア アプリと同様に OTA でのみ更新できます。

ソースからコントロール センターをビルドする

コントロール センターのソースコードを取得するには、バンドルされていないアプリを統合するをご覧ください。

マルチディスプレイでのユーザーのプライバシー

コントロール センターを使用すると、すべての乗車者がすべてのディスプレイでメディア情報を確認できます。ユーザーに通知するには、ブロックしないプライバシー通知を挿入することをおすすめします。ディスプレイにログインする際に、システムレベルでこの設定を行うことをおすすめします。