Android Auto と Android Automotive OS(AAOS)は、アプリのメディア ブラウザ サービスを呼び出して、利用可能なコンテンツを見つけます。これをサポートするには、メディア ブラウザ サービスにこれらの 2 つのメソッドを実装します。
onGetRoot を実装する
サービスの onGetRoot
メソッドは、コンテンツ階層のルートノードに関する情報を返します。Android Auto と AAOS はこのルートノードを使用して、onLoadChildren
メソッドで残りのコンテンツをリクエストします。次のコード スニペットは、onGetRoot
メソッドの実装を示しています。
Kotlin
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle?
): BrowserRoot? =
// Verify that the specified package is allowed to access your
// content. You'll need to write your own logic to do this.
if (!isValid(clientPackageName, clientUid)) {
// If the request comes from an untrusted package, return null.
// No further calls will be made to other media browsing methods.
null
} else MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null)
Java
@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
Bundle rootHints) {
// Verify that the specified package is allowed to access your
// content. You'll need to write your own logic to do this.
if (!isValid(clientPackageName, clientUid)) {
// If the request comes from an untrusted package, return null.
// No further calls will be made to other media browsing methods.
return null;
}
return new MediaBrowserServiceCompat.BrowserRoot(MY_MEDIA_ROOT_ID, null);
}
このメソッドの詳細な例については、GitHub の Universal Android Music Player サンプルアプリの onGetRoot
をご覧ください。
パッケージ検証を追加
サービスの onGetRoot
メソッドが呼び出されると、呼び出し元のパッケージは識別情報をサービスに渡します。サービスはこの情報を使用して、そのパッケージがコンテンツにアクセスできるかどうかを判断できます。
たとえば、アプリのコンテンツへのアクセスを承認済みパッケージのリストに限定できます。
clientPackageName
を許可リストと比較します。- パッケージの APK の署名に使用された証明書を検証します。
パッケージを検証できない場合は、null
を返してコンテンツへのアクセスを拒否します。
システムアプリ(Android Auto や AAOS など)にコンテンツへのアクセスを許可するには、システムアプリが onGetRoot
メソッドを呼び出すときに、サービスが null でない BrowserRoot
を返す必要があります。
AAOS システムアプリの署名は、自動車のメーカーやモデルによって異なります。AAOS をサポートするには、すべてのシステムアプリからの接続を許可してください。
次のコード スニペットは、呼び出し元のパッケージがシステムアプリであることをサービスが検証する方法を示しています。
fun isKnownCaller(
callingPackage: String,
callingUid: Int
): Boolean {
...
val isCallerKnown = when {
// If the system is making the call, allow it.
callingUid == Process.SYSTEM_UID -> true
// If the app was signed by the same certificate as the platform
// itself, also allow it.
callerSignature == platformSignature -> true
// ... more cases
}
return isCallerKnown
}
このコード スニペットは、GitHub の Universal Android Music Player サンプルアプリの PackageValidator
クラスからの抜粋です。サービスの onGetRoot
メソッドのパッケージ検証を実装する方法の詳細な例については、このクラスを参照してください。
システムアプリを許可するだけでなく、Google アシスタントが MediaBrowserService
に接続できるようにする必要もあります。Google アシスタントには、スマートフォン(Android Auto を含む)用と Android AAOS 用の個別のパッケージ名があります。
onLoadChildren を実装する
Android Auto と AAOS は、ルートノードのオブジェクトを受け取った後、そのオブジェクトで onLoadChildren
を呼び出してその子孫を取得することにより、最上位メニューを構築します。クライアント アプリは、子孫ノードのオブジェクトを使用してこの同じメソッドを呼び出すことにより、サブメニューを構築します。
コンテンツ階層の各ノードは、MediaBrowserCompat.MediaItem
オブジェクトで表されます。これらの各メディア アイテムは、一意の ID 文字列によって識別されます。クライアント アプリは、このような ID 文字列を不透明なトークンとして扱います。
クライアント アプリがサブメニューのブラウズまたはメディア アイテムの再生を行いたいときは、トークンを渡します。トークンを適切なメディア アイテムに関連付ける処理はアプリが行います。
このコード スニペットは、onLoadChildren
の実装を示しています。
Kotlin
override fun onLoadChildren(
parentMediaId: String,
result: Result<List<MediaBrowserCompat.MediaItem>>
) {
// Assume for example that the music catalog is already loaded/cached.
val mediaItems: MutableList<MediaBrowserCompat.MediaItem> = mutableListOf()
// Check if this is the root menu:
if (MY_MEDIA_ROOT_ID == parentMediaId) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems)
}
Java
@Override
public void onLoadChildren(final String parentMediaId,
final Result<List<MediaBrowserCompat.MediaItem>> result) {
// Assume for example that the music catalog is already loaded/cached.
List<MediaBrowserCompat.MediaItem> mediaItems = new ArrayList<>();
// Check if this is the root menu:
if (MY_MEDIA_ROOT_ID.equals(parentMediaId)) {
// Build the MediaItem objects for the top level
// and put them in the mediaItems list.
} else {
// Examine the passed parentMediaId to see which submenu we're at
// and put the descendants of that menu in the mediaItems list.
}
result.sendResult(mediaItems);
}
このメソッドの例については、GitHub の Universal Android Music Player サンプルアプリの onLoadChildren
をご覧ください。
ルートメニューを構造化する
Android Auto と Android Automotive OS には、ルートメニューの構造に関する特定の制約があります。これらの制約はルートヒントを介して MediaBrowserService
に伝えられます。ルートヒントは、onGetRoot()
に渡される Bundle 引数を介して読み取ることができます。これらのヒントに従うことで、システムはルート コンテンツをナビゲーション タブとして表示できます。これらのヒントに従わないと、一部のルート コンテンツが破棄されたり、システムによって検出されにくくなったりすることがあります。
図 1. ナビゲーション タブとして表示されるルート コンテンツ。
これらのヒントを適用することで、システムはルート コンテンツをナビゲーション タブとして表示します。これらのヒントを適用しないと、一部のルート コンテンツが破棄されたり、検出されにくくなったりすることがあります。これらのヒントは次のように送信されます。
ルートの子の上限数: ほとんどの場合、この数は 4 になります。つまり、表示できるタブは 4 つ以下です。
ルートの子でサポートされるフラグ: この値は
MediaItem#FLAG_BROWSABLE
になります。つまり、ブラウズ可能なアイテムのみをタブとして表示できます。再生可能なアイテムを表示することはできません。カスタム ブラウズ アクションの数の上限: サポートされているカスタム ブラウズ アクションの数を確認します。
Kotlin
import androidx.media.utils.MediaConstants
override fun onGetRoot(
clientPackageName: String,
clientUid: Int,
rootHints: Bundle
): BrowserRoot {
val maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4)
val supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE)
// Rest of method...
}
Java
import androidx.media.utils.MediaConstants;
// Later, in your MediaBrowserServiceCompat.
@Override
public BrowserRoot onGetRoot(
String clientPackageName, int clientUid, Bundle rootHints) {
int maximumRootChildLimit = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_LIMIT,
/* defaultValue= */ 4);
int supportedRootChildFlags = rootHints.getInt(
MediaConstants.BROWSER_ROOT_HINTS_KEY_ROOT_CHILDREN_SUPPORTED_FLAGS,
/* defaultValue= */ MediaItem.FLAG_BROWSABLE);
// Rest of method...
}
特に、階層の値が Android Auto と AAOS の外部の MediaBrowser
統合によって異なる場合に、これらのヒントの値に基づいてコンテンツ階層の構造のロジックを分岐することもできます。
たとえば、ルートの再生可能なアイテムを通常どおり表示する場合、サポートされるフラグヒントの値に従って、ルートのブラウズ可能なアイテムの下にネストできます。
タブを適切に表示するには、ルートヒントとは別に次のガイドラインにも従う必要があります。
各タブアイテムのモノクロ(白を推奨)アイコン
各タブアイテムに簡潔でわかりやすいラベルを付ける(ラベルが短ければ、ラベルが切り捨てられる可能性が低くなる)