Android Auto と Android Automotive OS は、メディアアプリのコンテンツを自動車に乗っているユーザーに届けます。自動車向けメディアアプリは、Android Auto と Android Automotive OS、またはメディア ブラウザ機能を持つ別のアプリがコンテンツを見つけて表示できるよう、メディア ブラウザ サービスを提供する必要があります。
このガイドは、音声を再生するメディアアプリがスマートフォンにすでにインストールされており、そのメディアアプリが Android メディアアプリ アーキテクチャに準拠していることを前提としています。
このガイドでは、アプリが Android Auto または Android Automotive OS 上で動作するうえで必須のコンポーネントである MediaBrowserService
と MediaSession
について説明します。核となるメディア インフラストラクチャが完成すると、Android Auto のサポートおよび Android Automotive OS のサポートをメディアアプリに追加できるようになります。
始める前に
- Android メディア API のドキュメントを確認してください。
- 設計に関するガイダンスについては、メディアアプリの作成を確認してください。
- このセクションに記載されている主な用語と概念を確認してください。
主な用語と概念
- メディア ブラウザ サービス
MediaBrowserServiceCompat
API に準拠するメディアアプリによって実装される Android サービス。アプリはこのサービスを使用してコンテンツを公開します。- メディア ブラウザ
- メディア ブラウザ サービスを見つけてコンテンツを表示するためにメディアアプリで使用される API。Android Auto と Android Automotive OS は、アプリのメディア ブラウザ サービスを見つけるためにメディア ブラウザを使用します。
- メディア アイテム
メディア ブラウザはそのコンテンツを
MediaItem
オブジェクトのツリーにまとめます。メディア アイテムには、次のフラグのいずれかまたは両方を含めることができます。FLAG_PLAYABLE
: アイテムがコンテンツ ツリーのリーフであることを示します。アイテムは、単一のサウンド ストリーム(アルバムの曲、オーディオ ブックのチャプター、ポッドキャストのエピソードなど)を表します。FLAG_BROWSABLE
: アイテムがコンテンツ ツリーのノードであり、子があることを示します(たとえば、アイテムがアルバムを表し、その子がアルバムの曲である場合など)。
ブラウズと再生の両方が可能なメディア アイテムは、プレイリストのような役割を果たします。アイテム自体を選択してそのすべての子を再生することも、アイテムの子をブラウズすることもできます。
- 自動車向け最適化
Android Automotive OS 設計ガイドラインに従った Android Automotive OS アプリのアクティビティ。このアクティビティのインターフェースは Android Automotive OS によって描画されないため、アプリが設計ガイドラインに従うように注意する必要があります。設計ガイドラインには通常、タップ ターゲットとフォントサイズを大きくする、日中モードと夜間モードをサポートする、コントラスト比を大きくする、といったものがあります。
自動車向けに最適化されたユーザー インターフェースは、自動車ユーザー エクスペリエンス制限(CUXR)が作動中でない場合にのみ表示できます。これらのインターフェースがユーザーに対して、長時間の注意や対話を求めることがあるためです。CUXR は、車が停止または駐車しているときは作動しませんが、車が動いているときは常に作動しています。
Android Auto はメディア ブラウザ サービスからの情報を使用して、独自の自動車向け最適化インターフェースを描画するため、Android Auto 用のアクティビティを設計する必要はありません。
アプリのマニフェスト ファイルを構成する
メディア ブラウザ サービスを作成するには、アプリのマニフェスト ファイルを事前に構成しておく必要があります。
メディア ブラウザ サービスを宣言する
Android Auto と Android Automotive OS はどちらも、メディア アイテムをブラウズするために、メディア ブラウザ サービスを介してアプリに接続します。マニフェストでメディア ブラウザ サービスを宣言し、Android Auto と Android Automotive OS がサービスを検出してアプリに接続できるようにします。
次のコード スニペットは、マニフェストでメディア ブラウザ サービスを宣言する方法を示しています。このコードは、Android Automotive OS モジュールのマニフェスト ファイルと、スマートフォン アプリのマニフェスト ファイルに追加する必要があります。
<application>
...
<service android:name=".MyMediaBrowserService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
...
</application>
アプリアイコンを指定する
Android Auto と Android Automotive OS がシステム UI でアプリを表示するためのアプリアイコンを指定する必要があります。次の 2 つのアイコンタイプが必要です。
- ランチャー アイコン
- アトリビューション アイコン
ランチャー アイコン
ランチャー アイコンは、ランチャーやアイコンのトレイなどのシステム UI で、アプリを表すアイコンです。次のマニフェスト宣言を使用することで、モバイルアプリのアイコンを使用して自動車メディアアプリを表すように指定できます。
<application
...
android:icon="@mipmap/ic_launcher"
...
/>
モバイルアプリとは異なるアイコンを使用するには、マニフェストでメディア ブラウザ サービスの <service>
要素に android:icon
プロパティを設定します。
<application>
...
<service
...
android:icon="@mipmap/auto_launcher"
...
/>
</application>
アトリビューション アイコン
アトリビューション アイコンは、メディアカードなど、メディア コンテンツが優先される場所で使用されます。通知用の小さなアイコンを再利用することを検討してください。 このアイコンはモノクロにする必要があります。次のマニフェスト宣言を使用して、アプリを表すために使用するアイコンを指定できます。
<application>
...
<meta-data
android:name="androidx.car.app.TintableAttributionIcon"
android:resource="@drawable/ic_status_icon" />
...
</application>
メディア ブラウザ サービスを作成する
メディア ブラウザ サービスを作成するには、MediaBrowserServiceCompat
クラスを拡張します。これにより、Android Auto と Android Automotive OS の両方で、サービスを使用して次の処理を実行できます。
- アプリのコンテンツ階層を参照して、ユーザーにメニューを表示する。
- アプリの
MediaSessionCompat
オブジェクトのトークンを取得して、音声の再生を制御する。
メディア ブラウザ サービスを使用して、他のクライアントがアプリからメディア コンテンツにアクセスできるようにすることも可能です。このメディア クライアントは、ユーザーのスマートフォン上の他のアプリでも、他のリモート クライアントでもかまいません。
メディア ブラウザ サービスのワークフロー
このセクションでは、一般的なユーザー ワークフローで Android Automotive OS と Android Auto がメディア ブラウザ サービスと対話する仕組みについて説明します。
- ユーザーが Android Automotive OS または Android Auto でアプリを起動します。
- Android Automotive OS または Android Auto は、
onCreate()
メソッドを使用してアプリのメディア ブラウザ サービスにコンタクトします。onCreate()
メソッドの実装では、MediaSessionCompat
オブジェクトとそのコールバック オブジェクトを作成して登録する必要があります。 - Android Automotive OS または Android Auto は、サービスの
onGetRoot()
メソッドを呼び出して、コンテンツ階層のルートのメディア アイテムを取得します。ルートのメディア アイテムは表示されませんが、アプリからより多くのコンテンツを取得するために使用されます。 - Android Automotive OS または Android Auto は、サービスの
onLoadChildren()
メソッドを呼び出して、ルートのメディア アイテムの子を取得します。Android Automotive OS と Android Auto は、これらのメディア アイテムを最上位のコンテンツ アイテムとして表示します。このレベルでシステムが表示するコンテンツについて詳しくは、このページのルートメニューを構造化するをご覧ください。 - ユーザーがブラウズ可能なメディア アイテムを選択すると、サービスの
onLoadChildren()
メソッドが再度呼び出され、選択されたメニュー アイテムの子が取得されます。 - ユーザーが再生可能なメディア アイテムを選択すると、Android Automotive OS または Android Auto は、適切なメディア セッション コールバック メソッドを呼び出して、その操作を実行します。
- アプリでサポートされていれば、ユーザーはコンテンツを検索することもできます。この場合、Android Automotive OS または Android Auto は、サービスの
onSearch()
メソッドを呼び出します。
コンテンツ階層を構築する
Android Auto と Android Automotive OS は、アプリのメディア ブラウザ サービスを呼び出して、利用可能なコンテンツを見つけます。これをサポートするには、メディア ブラウザ サービスに onGetRoot()
と onLoadChildren()
の 2 つのメソッドを実装する必要があります。
onGetRoot を実装する
サービスの onGetRoot()
メソッドは、コンテンツ階層のルートノードに関する情報を返します。Android Auto と Android Automotive OS はこのルートノードを使用して、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); }
このメソッドの詳細な例については、onGetRoot()
をご覧ください。
メソッド(GitHub の Universal Android Music Player サンプルアプリ)をご覧ください。
onGetRoot() のパッケージ検証を追加する
サービスの onGetRoot()
メソッドが呼び出されると、呼び出し元のパッケージは識別情報をサービスに渡します。サービスはこの情報を使用して、そのパッケージがコンテンツにアクセスできるかどうかを判断できます。たとえば、clientPackageName
を許可リストと照合して、パッケージの APK の署名に使用される証明書を確認することにより、アプリのコンテンツへのアクセスを承認されたパッケージのリストに限定できます。パッケージを検証できない場合は、null
を返してコンテンツへのアクセスを拒否します。
システムアプリ(Android Auto や Android Automotive OS など)にコンテンツへのアクセスを許可するには、システムアプリが onGetRoot()
メソッドを呼び出すときに、常にサービスが null でない BrowserRoot
を返す必要があります。Android Automotive OS システムアプリの署名は自動車のメーカーやモデルによって異なる可能性があるため、確実に Android Automotive OS をサポートできるように、すべてのシステムアプリからの接続を許可する必要があります。
次のコード スニペットは、呼び出し元のパッケージがシステムアプリであることをサービスが検証する方法を示しています。
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
}
このコード スニペットは PackageValidator
からの抜粋です。
クラスをご覧ください。サービスの onGetRoot()
メソッドのパッケージ検証を実装する方法の詳細な例については、このクラスを参照してください。
システムアプリを許可するだけでなく、Google アシスタントが MediaBrowserService
に接続できるようにする必要もあります。Google アシスタントには、スマートフォン(Android Auto を含む)用と Android Automotive OS 用の個別のパッケージ名があります。
onLoadChildren() を実装する
Android Auto と Android Automotive OS は、ルートノードのオブジェクトを受け取った後、そのオブジェクトで 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 whether 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 children 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 whether 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 children of that menu in the mediaItems list. } result.sendResult(mediaItems); }
この方法の詳細な例については、
onLoadChildren()
メソッド(GitHub の Universal Android Music Player サンプルアプリ)をご覧ください。
ルートメニューを構造化する
Android Auto と Android Automotive OS には、ルートメニューの構造に関する特定の制約があります。これらの制約はルートヒントを介して MediaBrowserService
に伝えられます。ルートヒントは、onGetRoot()
に渡される Bundle
引数を介して読み取ることができます。これらのヒントに従うことで、システムはルート コンテンツをナビゲーション タブとして最適に表示できます。これらのヒントに従わないと、一部のルート コンテンツが破棄されたり、システムによって検出されにくくなったりすることがあります。次の 2 つのヒントが送信されます。
- ルートの子の上限数: ほとんどの場合、この数は 4 になります。つまり、5 つ以上のタブを表示することはできません。
- ルートの子でサポートされるフラグ: この値は
MediaItem#FLAG_BROWSABLE
になります。つまり、ブラウズ可能なアイテムのみをタブとして表示できます。再生可能なアイテムを表示することはできません。
関連するルートヒントを読み取るには、次のコードを使用します。
Kotlin
import androidx.media.utils.MediaConstants // Later, in your MediaBrowserServiceCompat. 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 と Android Automotive OS の外部の MediaBrowser
統合によって異なる場合に、これらのヒントの値に基づいてコンテンツ階層の構造のロジックを分岐することもできます。たとえば、ルートの再生可能なアイテムを通常どおり表示する場合、サポートされるフラグヒントの値に従って、ルートのブラウズ可能なアイテムの下にネストできます。
タブを適切に表示するには、ルートヒントとは別に次のガイドラインにも従う必要があります。
- 各タブアイテムに、モノクロのアイコン(白を推奨)を付けます。
- 各タブアイテムに、簡潔でわかりやすいラベルを付けます。ラベルを短くすることにより、文字列が切り捨てられる可能性が低くなります。
メディアのアートワークを表示する
メディア アイテムのアートワークは、ContentResolver.SCHEME_CONTENT
または ContentResolver.SCHEME_ANDROID_RESOURCE
を使用してローカル URI として渡す必要があります。このローカル URI は、アプリのリソースでビットマップまたはベクター型ドローアブルに解決される必要があります。コンテンツ階層内のアイテムを表す MediaDescriptionCompat
オブジェクトの場合は、setIconUri()
を介して URI を渡します。現在再生中のアイテムを表す MediaMetadataCompat
オブジェクトの場合は、putString()
を介して、次のいずれかのキーを使用して URI を渡します。
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI
MediaMetadataCompat.METADATA_KEY_ART_URI
MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI
ウェブ URI からアートをダウンロードして、ローカル URI で公開する手順は次のとおりです。より詳細な例については、
実装
openFile()
と Universal Android Music の関連メソッド
Player サンプルアプリ。
ウェブ URI に対応する
content://
URI を作成します。メディア ブラウザ サービスとメディア セッションは、このコンテンツ URI を Android Auto と Android Automotive OS に渡します。Kotlin
fun Uri.asAlbumArtContentURI(): Uri { return Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CONTENT_PROVIDER_AUTHORITY) .appendPath(this.getPath()) // Make sure you trust the URI .build() }
Java
public static Uri asAlbumArtContentURI(Uri webUri) { return new Uri.Builder() .scheme(ContentResolver.SCHEME_CONTENT) .authority(CONTENT_PROVIDER_AUTHORITY) .appendPath(webUri.getPath()) // Make sure you trust the URI! .build(); }
ContentProvider.openFile()
の実装で、対応する URI のファイルが存在するかどうかを確認します。存在しない場合、画像ファイルをダウンロードしてキャッシュに保存します。次のコード スニペットでは Glide を使用しています。Kotlin
override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? { val context = this.context ?: return null val file = File(context.cacheDir, uri.path) if (!file.exists()) { val remoteUri = Uri.Builder() .scheme("https") .authority("my-image-site") .appendPath(uri.path) .build() val cacheFile = Glide.with(context) .asFile() .load(remoteUri) .submit() .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS) cacheFile.renameTo(file) file = cacheFile } return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY) }
Java
@Nullable @Override public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException { Context context = this.getContext(); File file = new File(context.getCacheDir(), uri.getPath()); if (!file.exists()) { Uri remoteUri = new Uri.Builder() .scheme("https") .authority("my-image-site") .appendPath(uri.getPath()) .build(); File cacheFile = Glide.with(context) .asFile() .load(remoteUri) .submit() .get(DOWNLOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS); cacheFile.renameTo(file); file = cacheFile; } return ParcelFileDescriptor.open(file, ParcelFileDescriptor.MODE_READ_ONLY); }
コンテンツ プロバイダについて詳しくは、コンテンツ プロバイダの作成をご覧ください。
コンテンツ スタイルを適用する
ブラウズ可能または再生可能なアイテムでコンテンツ階層を構築した後、コンテンツ スタイルを適用できます。自動車内でアイテムがどのように表示されるかは、このコンテンツ スタイルによって決まります。
使用可能なコンテンツ スタイルは次のとおりです。
- リストアイテム
-
このコンテンツ スタイルは、画像よりもタイトルとメタデータを優先します。
- グリッド アイテム
-
このコンテンツ スタイルは、タイトルとメタデータよりも画像を優先します。
デフォルトのコンテンツ スタイルを設定する
サービスの onGetRoot()
メソッドの BrowserRoot
エクストラ バンドルに特定の定数を含めることにより、メディア アイテムをどのように表示するかに関するグローバルなデフォルトを設定できます。Android Auto と Android Automotive OS はこのバンドルを読み取り、そうした定数を見つけて、適切なスタイルを決定します。
次のエクストラはバンドルでキーとして使用できます。
DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
: ブラウズツリー内のすべてのブラウズ可能なアイテムのプレゼンテーション ヒントを示します。DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
: ブラウズツリー内のすべての再生可能なアイテムのプレゼンテーション ヒントを示します。
キーは、次の整数定数値にマッピングして、こうしたアイテムの表示に影響を与えます。
DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM
: 対応するアイテムはリストアイテムとして表示されます。DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM
: 対応するアイテムはグリッド アイテムとして表示されます。DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM
: 対応するアイテムは、「カテゴリ」リストアイテムとして表示されます。これらは通常のリストアイテムと同じですが、アイテムのアイコンは小さい方が見栄えがよいため、周囲に余白を付けます。アイコンは、着色可能なベクター型ドローアブルにする必要があります。このヒントはブラウズ可能なアイテムに対してのみ提供されます。DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_GRID_ITEM
: 対応するアイテムは、「カテゴリ」グリッド アイテムとして表示されます。これらは通常のグリッド アイテムと同じですが、アイテムのアイコンは小さい方が見栄えがよいため、周囲に余白を付けます。アイコンは、着色可能なベクター型ドローアブルにする必要があります。このヒントはブラウズ可能なアイテムに対してのみ提供されます。
次のコード スニペットは、ブラウズ可能なアイテムと再生可能なアイテムのデフォルトのコンテンツ スタイルを、それぞれグリッドとリストに設定する方法を示しています。
Kotlin
import androidx.media.utils.MediaConstants @Nullable override fun onGetRoot( @NonNull clientPackageName: String, clientUid: Int, @Nullable rootHints: Bundle ): BrowserRoot { val extras = Bundle() extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM) return BrowserRoot(ROOT_ID, extras) }
Java
import androidx.media.utils.MediaConstants; @Nullable @Override public BrowserRoot onGetRoot( @NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { Bundle extras = new Bundle(); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM); return new BrowserRoot(ROOT_ID, extras); }
アイテムごとのコンテンツ スタイルを設定する
Content Style API を使用すると、ブラウズ可能なメディア アイテムの子やメディア アイテム自体の、デフォルトのコンテンツ スタイルをオーバーライドできます。
ブラウズ可能なメディア アイテムの子のデフォルトをオーバーライドするには、そのメディア アイテムの MediaDescription
にエクストラ バンドルを作成し、前述のヒントを追加します。DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE
はそのアイテムの再生可能な子に適用され、DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE
はそのアイテムのブラウズ可能な子に適用されます。
特定のメディア アイテム自体(子ではない)のデフォルトをオーバーライドするには、そのメディア アイテムの MediaDescription
にエクストラ バンドルを作成し、キー DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM
を使用してヒントを追加します。そのアイテムの表示を指定するには、前述の値と同じ値を使用します。
次のコード スニペットは、自身と子のデフォルトのコンテンツ スタイルをオーバーライドするブラウズ可能な MediaItem
を作成する方法を示しています。自身をカテゴリ リストアイテムとして、ブラウズ可能な子をリストアイテムとして、再生可能な子をグリッド アイテムとしてスタイル設定します。
Kotlin
import androidx.media.utils.MediaConstants private fun createBrowsableMediaItem( mediaId: String, folderName: String, iconUri: Uri ): MediaBrowser.MediaItem { val mediaDescriptionBuilder = MediaDescription.Builder() mediaDescriptionBuilder.setMediaId(mediaId) mediaDescriptionBuilder.setTitle(folderName) mediaDescriptionBuilder.setIconUri(iconUri) val extras = Bundle() extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM) mediaDescriptionBuilder.setExtras(extras) return MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE) }
Java
import androidx.media.utils.MediaConstants; private MediaBrowser.MediaItem createBrowsableMediaItem( String mediaId, String folderName, Uri iconUri) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId(mediaId); mediaDescriptionBuilder.setTitle(folderName); mediaDescriptionBuilder.setIconUri(iconUri); Bundle extras = new Bundle(); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_SINGLE_ITEM, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_BROWSABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_LIST_ITEM); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_PLAYABLE, MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM); mediaDescriptionBuilder.setExtras(extras); return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), MediaBrowser.MediaItem.FLAG_BROWSABLE); }
タイトルのヒントを使用してアイテムをグループ化する
関連するメディア アイテムをグループ化するには、アイテムごとにヒントを使用します。グループ内のすべてのメディア アイテムで、キー DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE
と同一の文字列値を持つマッピングを含む MediaDescription
でエクストラ バンドルを宣言する必要があります。グループのタイトルとして使用されるこの文字列をローカライズします。
次のコード スニペットは、サブグループの見出しが "Songs"
の MediaItem
を作成する方法を示しています。
Kotlin
import androidx.media.utils.MediaConstants private fun createMediaItem( mediaId: String, folderName: String, iconUri: Uri ): MediaBrowser.MediaItem { val mediaDescriptionBuilder = MediaDescription.Builder() mediaDescriptionBuilder.setMediaId(mediaId) mediaDescriptionBuilder.setTitle(folderName) mediaDescriptionBuilder.setIconUri(iconUri) val extras = Bundle() extras.putString( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs") mediaDescriptionBuilder.setExtras(extras) return MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), /* playable or browsable flag*/) }
Java
import androidx.media.utils.MediaConstants; private MediaBrowser.MediaItem createMediaItem(String mediaId, String folderName, Uri iconUri) { MediaDescription.Builder mediaDescriptionBuilder = new MediaDescription.Builder(); mediaDescriptionBuilder.setMediaId(mediaId); mediaDescriptionBuilder.setTitle(folderName); mediaDescriptionBuilder.setIconUri(iconUri); Bundle extras = new Bundle(); extras.putString( MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs"); mediaDescriptionBuilder.setExtras(extras); return new MediaBrowser.MediaItem( mediaDescriptionBuilder.build(), /* playable or browsable flag*/); }
アプリは、連続したブロックとしてグループ化するメディア アイテムをすべて渡す必要があります。たとえば、メディア アイテムの 2 つのグループ「Songs」と「Albums」をこの順序で表示するために、アプリで 5 つのメディア アイテムを次の順序で渡したとします。
- メディア アイテム A(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム B(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
を使用) - メディア アイテム C(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム D(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム E(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
を使用)
「Songs」グループと「Albums」グループのメディア アイテムは連続したブロックにならないため、Android Auto と Android Automotive OS はこれを次の 4 つのグループと解釈します。
- メディア アイテム A を含む「Songs」というグループ 1
- メディア アイテム B を含む「Albums」というグループ 2
- メディア アイテム C と D を含む「Songs」というグループ 3
- メディア アイテム E を含む「Albums」というグループ 4
これらのアイテムを 2 つのグループで表示するには、アプリで次の順序でメディア アイテムを渡す必要があります。
- メディア アイテム A(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム C(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム D(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Songs")
を使用) - メディア アイテム B(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
を使用) - メディア アイテム E(
extras.putString(MediaConstants.DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE, "Albums")
を使用)
追加のメタデータ インジケーターを表示する
追加のメタデータ インジケーターを設定して、メディア ブラウザツリー内に、またはメディアの再生中に、コンテンツが一目でわかる情報を提供できます。ブラウザツリー内では、Android Auto と Android Automotive OS はアイテムに関連付けられたエクストラを読み取り、特定の定数を見つけて、表示するインジケーターを決定します。メディアの再生中には、Android Auto と Android Automotive OS はメディア セッションのメタデータを読み取り、特定の定数を見つけて、表示するインジケーターを決定します。
次の定数は、MediaItem
ディスクリプション エクストラと MediaMetadata
エクストラの両方で使用できます。
EXTRA_DOWNLOAD_STATUS
: アイテムのダウンロード ステータスを示します。この定数をキーとして使用します。有効な値は次の long 定数のいずれかです。STATUS_DOWNLOADED
: アイテムは完全にダウンロードされています。STATUS_DOWNLOADING
: アイテムはダウンロード中です。STATUS_NOT_DOWNLOADED
: アイテムはダウンロードされていません。
METADATA_KEY_IS_EXPLICIT
: アイテムに露骨な表現のコンテンツが含まれているかどうかを示します。アイテムが露骨な表現であることを示すには、この定数をキーとして使用し、long 型のMETADATA_VALUE_ATTRIBUTE_PRESENT
を値として使用します。
次の定数は、MediaItem
ディスクリプション エクストラでしか使用できません。
DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
: 長編コンテンツ(ポッドキャストのエピソードやオーディオブックなど)の完了状態を示します。この定数をキーとして使用します。有効な値は次の整数定数のいずれかです。DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_NOT_PLAYED
: アイテムはまったく再生されていません。DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED
: アイテムは部分的に再生され、現在の位置は中間のどこかです。DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_FULLY_PLAYED
: アイテムは完了しました。
DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
: 長編コンテンツの完了進捗度を 0.0 以上 1.0 以下の double 型の値で示します。このエクストラは、PARTIALLY_PLAYING
状態に関する詳細情報を提供します。これにより、Android Auto または Android Automotive OS は、わかりやすい進行状況インジケーター(進行状況バーなど)を表示できます。このエクストラを使用する場合は、初回インプレッション後にインジケーターを最新の状態に保つ方法について、このガイドのコンテンツの再生中にブラウズビューの進行状況バーを更新するをご覧ください。
ユーザーがメディア ブラウズ ツリーをブラウジングしているときにインジケーターを表示するには、上の定数を 1 つ以上含むエクストラ バンドルを作成し、そのバンドルを MediaDescription.Builder.setExtras()
メソッドに渡します。
次のコード スニペットは、70% 完了した露骨な表現のメディア アイテムのインジケーターを表示する方法を示しています。
Kotlin
import androidx.media.utils.MediaConstants val extras = Bundle() extras.putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS, MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED) extras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7) val description = MediaDescriptionCompat.Builder() .setMediaId(/*...*/) .setTitle(resources.getString(/*...*/)) .setExtras(extras) .build() return MediaBrowserCompat.MediaItem(description, /* flags */)
Java
import androidx.media.utils.MediaConstants; Bundle extras = new Bundle(); extras.putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT); extras.putInt( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS, MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED); extras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.7); MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId(/*...*/) .setTitle(resources.getString(/*...*/)) .setExtras(extras) .build(); return new MediaBrowserCompat.MediaItem(description, /* flags */);
現在再生中のメディア アイテムのインジケーターを表示するには、METADATA_KEY_IS_EXPLICIT
または EXTRA_DOWNLOAD_STATUS
の Long
形式の値を mediaSession
の MediaMetadataCompat
で宣言します。再生ビューに DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS
または DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
インジケーターを表示することはできません。
次のコード スニペットは、再生ビュー内の現在の曲が露骨な表現であり、かつダウンロードされていることを示す方法を示しています。
Kotlin
import androidx.media.utils.MediaConstants mediaSession.setMetadata( MediaMetadataCompat.Builder() .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name") .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name") .putString( MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString()) .putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) .putLong( MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS, MediaDescriptionCompat.STATUS_DOWNLOADED) .build())
Java
import androidx.media.utils.MediaConstants; mediaSession.setMetadata( new MediaMetadataCompat.Builder() .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, "Song Name") .putString( MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, "Artist name") .putString( MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, albumArtUri.toString()) .putLong( MediaConstants.METADATA_KEY_IS_EXPLICIT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) .putLong( MediaDescriptionCompat.EXTRA_DOWNLOAD_STATUS, MediaDescriptionCompat.STATUS_DOWNLOADED) .build());
コンテンツの再生中にブラウズビューの進行状況バーを更新する
前述のように、DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
エクストラを使用することで、再生途中のコンテンツの進行状況バーをブラウズビューに表示できます。ただし、ユーザーが Android Auto または Android Automotive OS から再生途中のコンテンツを再生し続けると、時間の経過とともにインジケーターが不正確になります。
Android Auto と Android Automotive OS で進行状況バーを最新の状態に保つために、MediaMetadataCompat
と PlaybackStateCompat
で追加情報を提供し、ブラウズビューで進行中のコンテンツをメディア アイテムにリンクできます。メディア アイテムで進行状況バーを自動更新するには、次の要件を満たす必要があります。
- 作成した
MediaItem
は、エクストラでDESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE
を 0.0 以上 1.0 以下の値で送信する必要があります。 MediaMetadataCompat
は、MediaItem
に渡されるメディア ID と等しい文字列値でMETADATA_KEY_MEDIA_ID
を送信する必要があります。PlaybackStateCompat
は、MediaItem
に渡されるメディア ID と等しい文字列値にマッピングされるキーPLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID
のエクストラを含む必要があります。
次のコード スニペットは、現在再生中のアイテムがブラウズビューのアイテムにリンクされていることを示す方法を表しています。
Kotlin
import androidx.media.utils.MediaConstants // When the MediaItem is constructed to show in the browse view. // Suppose the item was 25% complete when the user launched the browse view. val mediaItemExtras = Bundle() mediaItemExtras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25) val description = MediaDescriptionCompat.Builder() .setMediaId("my-media-id") .setExtras(mediaItemExtras) // ...and any other setters. .build() return MediaBrowserCompat.MediaItem(description, /* flags */) // Elsewhere, when the user has selected MediaItem for playback. mediaSession.setMetadata( MediaMetadataCompat.Builder() .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id") // ...and any other setters. .build()) val playbackStateExtras = Bundle() playbackStateExtras.putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id") mediaSession.setPlaybackState( PlaybackStateCompat.Builder() .setExtras(playbackStateExtras) // ...and any other setters. .build())
Java
import androidx.media.utils.MediaConstants; // When the MediaItem is constructed to show in the browse view. // Suppose the item was 25% complete when the user launched the browse view. Bundle mediaItemExtras = new Bundle(); mediaItemExtras.putDouble( MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.25); MediaDescriptionCompat description = new MediaDescriptionCompat.Builder() .setMediaId("my-media-id") .setExtras(mediaItemExtras) // ...and any other setters. .build(); return MediaBrowserCompat.MediaItem(description, /* flags */); // Elsewhere, when the user has selected MediaItem for playback. mediaSession.setMetadata( new MediaMetadataCompat.Builder() .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, "my-media-id") // ...and any other setters. .build()); Bundle playbackStateExtras = new Bundle(); playbackStateExtras.putString( MediaConstants.PLAYBACK_STATE_EXTRAS_KEY_MEDIA_ID, "my-media-id"); mediaSession.setPlaybackState( new PlaybackStateCompat.Builder() .setExtras(playbackStateExtras) // ...and any other setters. .build());
ブラウズ可能な検索結果を表示する
アプリは、ユーザーが検索クエリを開始したときに表示されるコンテキスト検索結果を提供できます。Android Auto と Android Automotive OS は、検索結果を、検索クエリ インターフェースや、セッション内で前に実行されたクエリにピボットされたアフォーダンスに表示します。詳細については、このガイドの音声操作をサポートするをご覧ください。
ブラウズ可能な検索結果を表示するには、定数キー BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED
をサービスの onGetRoot()
メソッドのエクストラ バンドルに含めて、ブール値 true
にマッピングします。
次のコード スニペットは、onGetRoot()
メソッドでサポートを有効にする方法を示しています。
Kotlin
import androidx.media.utils.MediaConstants @Nullable fun onGetRoot( @NonNull clientPackageName: String, clientUid: Int, @Nullable rootHints: Bundle ): BrowserRoot { val extras = Bundle() extras.putBoolean( MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true) return BrowserRoot(ROOT_ID, extras) }
Java
import androidx.media.utils.MediaConstants; @Nullable @Override public BrowserRoot onGetRoot( @NonNull String clientPackageName, int clientUid, @Nullable Bundle rootHints) { Bundle extras = new Bundle(); extras.putBoolean( MediaConstants.BROWSER_SERVICE_EXTRAS_KEY_SEARCH_SUPPORTED, true); return new BrowserRoot(ROOT_ID, extras); }
検索結果の提供を開始するには、メディア ブラウザ サービスの onSearch()
メソッドをオーバーライドします。Android Auto と Android Automotive OS は、ユーザーが検索クエリ インターフェースまたは「検索結果」アフォーダンスを呼び出すたびに、ユーザーの検索キーワードをこのメソッドに転送します。
サービスの onSearch()
メソッドによる検索結果をタイトル アイテムで整理し、よりブラウズしやすくすることが可能です。たとえば、アプリで音楽を再生する場合、アルバム、アーティスト、曲ごとに検索結果をまとめます。
次のコード スニペットは、onSearch()
メソッドの単純な実装を示しています。
Kotlin
fun onSearch(query: String, extras: Bundle) { // Detach from results to unblock the caller (if a search is expensive). result.detach() object:AsyncTask() { internal var searchResponse:ArrayList internal var succeeded = false protected fun doInBackground(vararg params:Void):Void { searchResponse = ArrayList() if (doSearch(query, extras, searchResponse)) { succeeded = true } return null } protected fun onPostExecute(param:Void) { if (succeeded) { // Sending an empty List informs the caller that there were no results. result.sendResult(searchResponse) } else { // This invokes onError() on the search callback. result.sendResult(null) } return null } }.execute() } // Populates resultsToFill with search results. Returns true on success or false on error. private fun doSearch( query: String, extras: Bundle, resultsToFill: ArrayList ): Boolean { // Implement this method. }
Java
@Override public void onSearch(final String query, final Bundle extras, Result<List<MediaItem>> result) { // Detach from results to unblock the caller (if a search is expensive). result.detach(); new AsyncTask<Void, Void, Void>() { List<MediaItem> searchResponse; boolean succeeded = false; @Override protected Void doInBackground(Void... params) { searchResponse = new ArrayList<MediaItem>(); if (doSearch(query, extras, searchResponse)) { succeeded = true; } return null; } @Override protected void onPostExecute(Void param) { if (succeeded) { // Sending an empty List informs the caller that there were no results. result.sendResult(searchResponse); } else { // This invokes onError() on the search callback. result.sendResult(null); } } }.execute() } /** Populates resultsToFill with search results. Returns true on success or false on error. */ private boolean doSearch(String query, Bundle extras, ArrayList<MediaItem> resultsToFill) { // Implement this method. }
カスタム ブラウズ アクション
カスタム ブラウズ アクションを使用して、車のメディアアプリでアプリの MediaItem
オブジェクトにカスタムのアイコンとラベルを追加し、それらのアクションのユーザー操作を処理することができます。これにより、[Download]、[Add to Queue]、[Play Radio]、[Favorite]、[Remove] といったアクションの追加など、さまざまな方法でメディアアプリの機能を拡張できます。
OEM に表示が許可されているカスタム アクションの数より多い場合は、オーバーフロー メニューがユーザーに表示されます。
仕組み
各カスタム ブラウズ アクションは以下で定義されます。
- アクション ID(一意の文字列識別子)
- アクション ラベル(ユーザーに表示されるテキスト)
- アクション アイコンの URI(色合いを調整できるベクター型ドローアブル)
カスタム ブラウズ アクションのリストは、BrowseRoot
の一部としてグローバルに定義します。定義したら、各 MediaItem.
にこれらのアクションのサブセットをアタッチできます。
ユーザーがカスタム ブラウズ アクションを操作すると、アプリが onCustomAction()
でコールバックを受け取ります。その後、必要に応じて、MediaItem
に対してアクションを処理し、アクション リストを更新することができます。これは、[Favorite]、[Download] などのステートフルなアクションに役立ちます。[Play Radio] など、更新が必要ないアクションでは、アクション リストを更新する必要はありません。
ブラウズノードのルートにカスタム ブラウズ アクションをアタッチすることもできます。アタッチしたアクションは、メイン ツールバーの下のセカンダリ ツールバーに表示されます。
カスタム ブラウズ アクションを実装する方法
以下に、プロジェクトにカスタム ブラウズ アクションを追加する手順を示します。
MediaBrowserServiceCompat
の実装で次の 2 つのメソッドをオーバーライドします。- 実行時にアクションの上限を解析します。
onGetRoot()
で、rootHints
Bundle
にキーBROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT
を使用してMediaItem
ごとに許可されるアクションの上限数を取得します。上限 0 は、この機能がシステムでサポートされていないことを示します。
- カスタム ブラウズ アクションのグローバル リストを作成します。
- アクションごとに、次のキーを使って
Bundle
オブジェクトを作成します。 *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
: アクション ID *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
: アクション ラベル *EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
: アクション アイコンの URI * アクションのBundle
オブジェクトすべてをリストに追加します。
- アクションごとに、次のキーを使って
BrowseRoot
にグローバル リストを追加します。BrowseRoot
のエクストラBundle
で、キーBROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST
を使用してParcelable
Arraylist
としてアクションのリストを追加します。
MediaItem
オブジェクトにアクションを追加します。- 各
MediaItem
オブジェクトにアクションを追加するには、キーDESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST
を使用してMediaDescriptionCompat
エクストラにアクション ID のリストを含めます。このリストは、BrowseRoot
で定義したアクションのグローバル リストのサブセットにする必要があります。
- 各
- アクションを処理し、進行状況または結果を返します。
onCustomAction
で、アクション ID と必要なその他のデータに基づいてアクションを処理します。アクションをトリガーしたMediaItem
の ID は、キーEXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID
を使用してエクストラから取得できます。MediaItem
に対するアクションのリストを更新するには、進行状況または結果バンドルにキーEXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
を含めます。
次に、カスタム ブラウズ アクションを使い始めるにあたって BrowserServiceCompat
に加えることができる変更について説明します。
BrowserServiceCompat をオーバーライドする
MediaBrowserServiceCompat
で以下のメソッドをオーバーライドする必要があります。
public void onLoadItem(String itemId, @NonNull Result<MediaBrowserCompat.MediaItem> result)
public void onCustomAction(@NonNull String action, Bundle extras, @NonNull Result<Bundle> result)
アクション数の上限を解析する
サポートされているカスタム ブラウズ アクションの数を確認する必要があります。
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { rootHints.getInt( MediaConstants.BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT, 0) }
カスタム ブラウズ アクションを作成する
各アクションは個別の Bundle
にパックする必要があります。
- アクション ID
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID, "<ACTION_ID>")
- アクション ラベル
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL, "<ACTION_LABEL>")
- アクション アイコンの URI
bundle.putString(MediaConstants.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, "<ACTION_ICON_URI>")
Parceable
ArrayList
にカスタム ブラウズ アクションを追加する
カスタム ブラウズ アクションの Bundle
オブジェクトをすべて ArrayList
に追加します。
private ArrayList<Bundle> createCustomActionsList( CustomBrowseAction browseActions) { ArrayList<Bundle> browseActionsBundle = new ArrayList<>(); for (CustomBrowseAction browseAction : browseActions) { Bundle action = new Bundle(); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID, browseAction.mId); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL, getString(browseAction.mLabelResId)); action.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI, browseAction.mIcon); browseActionsBundle.add(action); } return browseActionsBundle; }
ブラウズルートにカスタム ブラウズ アクション リストを追加する
public BrowserRoot onGetRoot(@NonNull String clientPackageName, int clientUid, Bundle rootHints) { Bundle browserRootExtras = new Bundle(); browserRootExtras.putParcelableArrayList( BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST, createCustomActionsList())); mRoot = new BrowserRoot(ROOT_ID, browserRootExtras); return mRoot; }
MediaItem
にアクションを追加する
MediaDescriptionCompat buildDescription (long id, String title, String subtitle, String description, Uri iconUri, Uri mediaUri, ArrayList<String> browseActionIds) { MediaDescriptionCompat.Builder bob = new MediaDescriptionCompat.Builder(); bob.setMediaId(id); bob.setTitle(title); bob.setSubtitle(subtitle); bob.setDescription(description); bob.setIconUri(iconUri); bob.setMediaUri(mediaUri); Bundle extras = new Bundle(); extras.putStringArrayList( DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST, browseActionIds); bob.setExtras(extras); return bob.build(); } MediaItem mediaItem = new MediaItem(buildDescription(...), flags);
onCustomAction
の結果を作成する
Bundle extras
から mediaId を解析します。@Override public void onCustomAction( @NonNull String action, Bundle extras, @NonNull Result<Bundle> result){ String mediaId = extras.getString(MediaConstans.EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID); }
- 非同期の結果の場合は、
result.detach()
で結果をデタッチする - 結果バンドルを作成する
- ユーザーへのメッセージ
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE, mContext.getString(stringRes))
- アイテムの更新(アイテム内のアクションの更新に使用)
mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
- 再生ビューを開く
//Shows user the PBV without changing the playback state mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
- ブラウズノードの更新
//Change current browse node to mediaId mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
- ユーザーへのメッセージ
- エラーの場合は、
result.sendError(resultBundle).
を呼び出す - 進行状況の更新の場合は、
result.sendProgressUpdate(resultBundle)
を呼び出す result.sendResult(resultBundle)
を呼び出して終了する
アクションの状態を更新する
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
キーと result.sendProgressUpdate(resultBundle)
メソッドを使用して、MediaItem
を更新し、アクションの新しい状態を反映できます。これにより、アクションの進行状況と結果に関するリアルタイムのフィードバックをユーザーに提供できます。
例: Download アクション
以下に、この機能を使用して 3 つの状態を持つ Download アクションを実装する方法の例を示します。
- Download: アクションの最初の状態です。このアクションが選択されたら、[Downloading] に切り替え、
sendProgressUpdate
を呼び出して UI を更新できます。 - Downloading: ダウンロード中であることを示す状態です。この状態を使用して、進行状況バーなどのインジケーターをユーザーに表示できます。
- Downloaded: ダウンロードが完了したことを示す状態です。ダウンロードが終了したら、[Downloading] を [Downloaded] に切り替え、
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
キーを使用してsendResult
を呼び出し、アイテムの更新が必要であることを示します。また、EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE
キーを使用してユーザーに完了メッセージを表示することもできます。
この方法により、ダウンロード プロセスとダウンロードの現在の状態についてユーザーに明確なフィードバックを提供できます。25%、50%、75% のダウンロード状態を示すアイコンを使用して、より詳しい情報を追加することもできます。
例: Favorite アクション
もう一つの例は、2 つの状態を持つ Favorite アクションです。
- Favorite: ユーザーのお気に入りリストにないアイテムに対して表示されるアクションです。このアクションが選択されたら、[Favorited] に切り替え、
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
キーでsendResult
を呼び出して UI を更新できます。 - Favorited: ユーザーのお気に入りリストにあるアイテムに対して表示されるアクションです。このアクションが選択されたら、[Favorite] に切り替え、
EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM
キーでsendResult
を呼び出して UI を更新できます。
この方法により、ユーザーはお気に入りのアイテムを明確かつ一貫した方法で管理できます。
これらの例を通して、カスタム ブラウズ アクションの柔軟性と、このアクションを使用してリアルタイムのフィードバックを含むさまざまな機能を実装する方法を把握し、車のメディアアプリのユーザー エクスペリエンス向上につなげることができます。
この機能の完全な実装例については、TestMediaApp
プロジェクトをご覧ください。
再生コントロールを有効にする
Android Auto と Android Automotive OS は、サービスの MediaSessionCompat
を介して再生コントロール コマンドを送信します。セッションを登録し、関連するコールバック メソッドを実装する必要があります。
メディア セッションを登録する
メディア ブラウザ サービスの onCreate()
メソッドで MediaSessionCompat
を作成し、setSessionToken()
を呼び出してメディア セッションを登録します。
次のコード スニペットは、メディア セッションを作成して登録する方法を示しています。
Kotlin
override fun onCreate() { super.onCreate() ... // Start a new MediaSession. val session = MediaSessionCompat(this, "session tag").apply { // Set a callback object that implements MediaSession.Callback // to handle play control requests. setCallback(MyMediaSessionCallback()) } sessionToken = session.sessionToken ... }
Java
public void onCreate() { super.onCreate(); ... // Start a new MediaSession. MediaSessionCompat session = new MediaSessionCompat(this, "session tag"); setSessionToken(session.getSessionToken()); // Set a callback object that implements MediaSession.Callback // to handle play control requests. session.setCallback(new MyMediaSessionCallback()); ... }
メディア セッション オブジェクトを作成する際に、再生コントロール リクエストの処理に使用されるコールバック オブジェクトを設定します。このコールバック オブジェクトを作成するには、アプリの MediaSessionCompat.Callback
クラスの実装を提供します。次のセクションで、このオブジェクトを実装する方法を説明します。
再生コマンドを実装する
ユーザーがアプリにメディア アイテムの再生をリクエストすると、Android Automotive OS と Android Auto は、アプリの MediaSessionCompat
オブジェクト(アプリのメディア ブラウザ サービスから取得したオブジェクト)の MediaSessionCompat.Callback
クラスを使用します。ユーザーがコンテンツ再生を制御する場合(再生の一時停止や次のトラックへのスキップなど)、Android Auto と Android Automotive OS は、コールバック オブジェクトのメソッドのひとつを呼び出します。
コンテンツ再生を処理するには、アプリで MediaSessionCompat.Callback
抽象クラスを拡張して、アプリがサポートするメソッドを実装する必要があります。
アプリが提供するコンテンツの種類に応じて、以下のコールバック メソッドをすべて実装します。
onPrepare()
- メディアソースが変更されたときに呼び出されます。Android Automotive OS は、起動直後にもこのメソッドを呼び出します。メディアアプリは、このメソッドを実装する必要があります。
onPlay()
- ユーザーが特定のアイテムを選択せずに再生を選択したときに呼び出されます。アプリはデフォルトのコンテンツを再生する必要があります。また、
onPause()
で再生が一時停止されていた場合、アプリは再生を再開します。注: Android Automotive OS または Android Auto がメディア ブラウザ サービスに接続したとき、アプリは自動的に音楽の再生を開始してはなりません。詳細については、最初の PlaybackState を設定するをご覧ください。
onPlayFromMediaId()
- ユーザーが特定のアイテムの再生を選択したときに呼び出されます。このメソッドには、メディア ブラウザ サービスがコンテンツ階層内のメディア アイテムに割り当てた ID が渡されます。
onPlayFromSearch()
- ユーザーが検索クエリからの再生を選択したときに呼び出されます。アプリは、渡された検索文字列に基づいて適切な選択を行う必要があります。
onPause()
- ユーザーが再生の一時停止を選択したときに呼び出されます。
onSkipToNext()
- ユーザーが次のアイテムへのスキップを選択したときに呼び出されます。
onSkipToPrevious()
- ユーザーが前のアイテムへのスキップを選択したときに呼び出されます。
onStop()
- ユーザーが再生の停止を選択したときに呼び出されます。
アプリでこれらのメソッドをオーバーライドして、必要な機能を提供します。メソッドの機能がアプリでサポートされていなければ、そのメソッドを実装する必要はありません。たとえば、アプリがライブ ストリーム(スポーツ放送など)を再生する場合、onSkipToNext()
メソッドを実装する必要はありません。代わりに onSkipToNext()
のデフォルト実装を使用できます。
アプリには、車載スピーカーからコンテンツを再生するための特別なロジックは不要です。アプリは、コンテンツの再生リクエストを受信したとき、ユーザーのスマートフォンのスピーカーまたはヘッドフォンでコンテンツを再生する場合と同じ方法で音声を再生できます。Android Auto と Android Automotive OS は、音声コンテンツを車載システムに自動的に送信して、車載スピーカーで再生します。
音声コンテンツの再生の詳細については、MediaPlayer の概要、オーディオ アプリの概要、ExoPlayer の概要をご覧ください。
標準の再生操作を設定する
Android Auto と Android Automotive OS は、PlaybackStateCompat
オブジェクトで有効化されている操作に基づいて再生コントロールを表示します。
デフォルトでは、アプリは次の操作をサポートする必要があります。
アプリのコンテンツに関連する場合、アプリは次の操作もサポートできます。
さらに、ユーザーに表示できる再生キューの作成も可能ですが、必須ではありません。そのためには、setQueue()
メソッドと setQueueTitle()
メソッドを呼び出し、ACTION_SKIP_TO_QUEUE_ITEM
操作を有効にして、コールバック onSkipToQueueItem()
を定義します。
また、現在再生中の曲のインジケーターである「この曲なに?」アイコンのサポートも追加します。そのためには、setActiveQueueItemId()
メソッドを呼び出し、現在再生しているアイテムの ID をキューに渡します。キューが変更されるたびに setActiveQueueItemId()
を更新する必要があります。
Android Auto と Android Automotive OS は、有効化された操作ごとにボタンを表示し、再生キューを表示します。ボタンがクリックされると、システムは MediaSessionCompat.Callback
から対応するコールバックを呼び出します。
未使用のスペースを予約する
Android Auto と Android Automotive OS は、ACTION_SKIP_TO_PREVIOUS
アクションと ACTION_SKIP_TO_NEXT
アクション用に UI のスペースを予約します。アプリがこれらの機能のいずれかをサポートしていない場合、Android Auto と Android Automotive OS はこのスペースを使用して、デベロッパーが作成したカスタム アクションを表示します。
このスペースにカスタム アクションを表示しない場合、アプリが対応する機能をサポートしていないときは常に Android Auto と Android Automotive OS がスペースを空白のままにしておくように、スペースを予約できます。そのためには、予約された各機能に対応する定数を含むエクストラ バンドルを指定して、setExtras()
メソッドを呼び出します。SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_NEXT
は ACTION_SKIP_TO_NEXT
に対応し、SESSION_EXTRAS_KEY_SLOT_RESERVATION_SKIP_TO_PREV
は ACTION_SKIP_TO_PREVIOUS
に対応します。これらの定数をバンドルのキーとして使用し、値にブール値 true
を使用します。
最初の PlaybackState を設定する
Android Auto と Android Automotive OS がメディア ブラウザ サービスと通信する際、メディア セッションは PlaybackStateCompat
を使用してコンテンツ再生のステータスをやり取りします。Android Automotive OS または Android Auto がメディア ブラウザ サービスに接続したとき、アプリは自動的に音楽の再生を開始してはなりません。Android Auto と Android Automotive OS に処理をまかせ、車の状態またはユーザーの操作に基づいて再生を再開または開始してください。
そのためには、メディア セッションの最初の PlaybackStateCompat
を、STATE_STOPPED
、STATE_PAUSED
、STATE_NONE
、STATE_ERROR
のいずれかに設定します。
Android Auto と Android Automotive OS のメディア セッションは運転している間だけ持続するため、ユーザーはこれらのセッションの開始と停止を頻繁に行うことになります。運転再開時のエクスペリエンスをよりシームレスなものにするには、ユーザーの以前のセッションの状態(最後に再生したメディア アイテム、PlaybackStateCompat
、キューなど)を追跡して、メディアアプリが再開リクエストを受け取ったときに、再生を中断したところから自動的に再開できるようにします。
カスタム再生操作を追加する
カスタム再生操作を追加して、メディアアプリがサポートする追加の操作を表示できます。スペースに余裕がある(予約されていない)場合、Android はトランスポート コントロールにカスタム操作を追加します。それ以外の場合、カスタム操作はオーバーフロー メニューに表示されます。カスタム アクションは、PlaybackStateCompat
に追加された順序で表示されます。
カスタム操作は、標準操作とは異なる動作を提供するために使用します。標準の操作の置き換えや複製には使用しないでください。
これらの操作は、PlaybackStateCompat.Builder
クラスの addCustomAction()
メソッドを使用して追加できます。
次のコード スニペットは、カスタムの「ラジオ チャンネルの開始」操作を追加する方法を示しています。
Kotlin
stateBuilder.addCustomAction( PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon ).run { setExtras(customActionExtras) build() } )
Java
stateBuilder.addCustomAction( new PlaybackStateCompat.CustomAction.Builder( CUSTOM_ACTION_START_RADIO_FROM_MEDIA, resources.getString(R.string.start_radio_from_media), startRadioFromMediaIcon) .setExtras(customActionExtras) .build());
このメソッドの詳細な例については、setCustomAction()
をご覧ください。
メソッド(GitHub の Universal Android Music Player サンプルアプリ)をご覧ください。
カスタム操作を作成した場合、メディア セッションは onCustomAction()
メソッドをオーバーライドすることで操作に応答できます。
次のコード スニペットは、アプリが「ラジオ チャンネルの開始」操作に応答する方法を示しています。
Kotlin
override fun onCustomAction(action: String, extras: Bundle?) { when(action) { CUSTOM_ACTION_START_RADIO_FROM_MEDIA -> { ... } } }
Java
@Override public void onCustomAction(@NonNull String action, Bundle extras) { if (CUSTOM_ACTION_START_RADIO_FROM_MEDIA.equals(action)) { ... } }
このメソッドの詳細な例については、onCustomAction
をご覧ください。
メソッド(GitHub の Universal Android Music Player サンプルアプリ)をご覧ください。
カスタム操作のアイコン
作成する各カスタム操作には、アイコン リソースが必要です。車載アプリはさまざまな画面サイズと密度で実行される可能性があるので、提供するアイコンはベクター型ドローアブルでなければなりません。ベクター型ドローアブルを使用すると、細部を犠牲にすることなくアセットを拡大 / 縮小できます。また、低い解像度でも、アイコンの端と隅をピクセル境界に簡単に合わせられます。
カスタム操作がステートフルである場合(再生設定のオンとオフを切り替える場合など)は、ユーザーが操作を選択したときに変化に気付けるように、状態ごとに別々のアイコンを提供します。
無効な操作に対して代替アイコン スタイルを提供する
現在のコンテキストでカスタム操作を使用できない場合は、カスタム操作のアイコンを、操作が無効であることを示す代替アイコンに切り替えます。
音声形式を指定する
現在再生中のメディアが特別な音声形式を使用していることを示すため、この機能に対応する自動車に表示するアイコンを指定できます。KEY_CONTENT_FORMAT_TINTABLE_LARGE_ICON_URI
と KEY_CONTENT_FORMAT_TINTABLE_SMALL_ICON_URI
は(MediaSession.setMetadata()
に渡す)現在再生中のメディア アイテムのエクストラ バンドルで設定できます。さまざまなレイアウトに対応できるよう、これらのエクストラは必ず両方とも設定してください。
さらに、KEY_IMMERSIVE_AUDIO
のエクストラを設定すると、これが没入感のある音声であることを自動車の OEM に伝えることができます。自動車の OEM は、没入感のあるコンテンツを妨げる可能性があるオーディオ エフェクトを適用するかどうかを非常に慎重に判断する必要があります。
現在再生中のアイテムからリンクを追加する
現在再生中のメディア アイテムのサブタイトル、説明、またはその両方が他のメディア アイテムへのリンクになるように設定できます。これにより、ユーザーは関連するアイテムにすばやくジャンプできます。たとえば、同じアーティストの他の曲や、ポッドキャストの他のエピソードなどにジャンプできます。車がこの機能をサポートしている場合、ユーザーはリンクをタップしてそのコンテンツを参照できます。
リンクを追加するには、KEY_SUBTITLE_LINK_MEDIA_ID
メタデータ(サブタイトルからリンクする場合)または KEY_DESCRIPTION_LINK_MEDIA_ID
(説明からリンクする場合)を設定します。詳しくは、これらのメタデータ フィールドの参照ドキュメントをご覧ください。
音声操作をサポートする
メディアアプリでは、ドライバーが注意散漫になる危険を最小限に抑える安全で便利なエクスペリエンスを提供するために、音声操作をサポートする必要があります。たとえば、アプリがあるメディア アイテムを再生しているときに、ユーザーが車載ディスプレイを見たり触れたりせずに、声(「[曲名] を再生して」など)で別の曲の再生をアプリに指示できるようにします。ユーザーは、ハンドル上の該当するボタンをクリックするか起動ワード(「OK Google」)を言うことで、クエリを開始できます。
Android Auto または Android Automotive OS が音声操作を検出して解釈すると、その音声操作は onPlayFromSearch()
を介してアプリに配信されます。このコールバックを受け取ると、アプリは query
文字列に一致するコンテンツを見つけて再生を開始します。
ユーザーは、ジャンル、アーティスト、アルバム、曲名、ラジオ局、プレイリストなど、クエリにさまざまなカテゴリの用語を指定できます。検索のサポートを構築する際は、アプリに適したすべてのカテゴリを考慮してください。Android Auto または Android Automotive OS は、クエリが特定のカテゴリに当てはまることを検出すると、extras
パラメータにエクストラを付加します。送信される可能性のあるエクストラは次のとおりです。
空の query
文字列を考慮に入れます。ユーザーが検索キーワードを指定しなかった場合、Android Auto または Android Automotive OS によってこの文字列が送信されることがあります(ユーザーが「音楽を再生して」と言った場合など)。アプリはその場合、最近再生したトラックまたは新しく提案されたトラックを開始するよう選択できます。
検索の処理に時間がかかる場合は、onPlayFromSearch()
でブロックしないでください。代わりに、再生状態を STATE_CONNECTING
に設定し、非同期スレッドで検索を行います。
再生が開始されたら、メディア セッションのキューに関連コンテンツを入力することを検討してください。たとえば、ユーザーがアルバムの再生をリクエストした場合、アプリはそのアルバムのトラックリストをキューに入力する可能性があります。ブラウズ可能な検索結果のサポートを実装することも検討してください。これにより、ユーザーはクエリと一致する別のトラックを選択できます。
「再生」クエリに加えて、Android Auto と Android Automotive OS は、「音楽を一時停止」や「次の曲」のような再生制御のための音声クエリを認識します。また、これらのコマンドを onPause()
や onSkipToNext()
のような該当するメディア セッション コールバックと照合します。
音声対応の再生操作をアプリに実装する方法の詳細な例については、Google アシスタントとメディアアプリをご覧ください。
注意散漫に対する安全保護対策を実装する
Android Auto の使用中、ユーザーのスマートフォンは車載スピーカーに接続されているため、ドライバーの注意散漫を防止するために追加の予防措置を講じる必要があります。
車内でのアラームを抑制する
Android Auto メディアアプリは、ユーザーが再生を開始した場合(再生ボタンを押した場合など)を除き、車載スピーカーで音声の再生を開始してはなりません。メディアアプリでユーザーがアラームをスケジュールした場合であっても、それによって車載スピーカーで音楽を再生してはいけません。
この要件を満たすために、アプリは音声を再生する前に、シグナルとして CarConnection
を使用できます。アプリは、自動車の接続タイプの LiveData
を監視し、CONNECTION_TYPE_PROJECTION
と合致するかどうかを確認することで、スマートフォンが車載ディスプレイに投影されているかどうかを確認できます。
ユーザーのスマートフォンが投影されている場合、アラームをサポートするメディアアプリは次のいずれかを行う必要があります。
- アラームを無効にする。
STREAM_ALARM
でアラームを再生し、アラームを無効にする UI をスマートフォン画面に表示する。
メディア広告を処理する
デフォルトでは、Android Auto は、音声再生セッション中にメディア メタデータが変更されると、通知を表示します。メディアアプリが音楽の再生から広告の掲載に切り替えたときに通知を表示すると、ユーザーの注意が散漫になります。この場合に Android Auto が通知を表示しないようにするには、次のコード スニペットに示すように、メディア メタデータのキー METADATA_KEY_IS_ADVERTISEMENT
を METADATA_VALUE_ATTRIBUTE_PRESENT
に設定する必要があります。
Kotlin
import androidx.media.utils.MediaConstants override fun onPlayFromMediaId(mediaId: String, extras: Bundle?) { MediaMetadataCompat.Builder().apply { if (isAd(mediaId)) { putLong( MediaConstants.METADATA_KEY_IS_ADVERTISEMENT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT) } // ...add any other properties you normally would. mediaSession.setMetadata(build()) } }
Java
import androidx.media.utils.MediaConstants; @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder(); if (isAd(mediaId)) { builder.putLong( MediaConstants.METADATA_KEY_IS_ADVERTISEMENT, MediaConstants.METADATA_VALUE_ATTRIBUTE_PRESENT); } // ...add any other properties you normally would. mediaSession.setMetadata(builder.build()); }
一般的なエラーを処理する
アプリでエラーが発生した場合は、再生状態を STATE_ERROR
に設定し、setErrorMessage()
メソッドを使用してエラー メッセージを提供します。エラー メッセージの設定時に使用できるエラーコードの一覧については、PlaybackStateCompat
をご覧ください。エラー メッセージはユーザー向けであるため、ユーザーの現在のロケールに合わせてローカライズする必要があります。これにより、Android Auto と Android Automotive OS はユーザーにエラー メッセージを表示できます。
たとえば、ユーザーの現在の地域でコンテンツを利用できない場合は、エラー メッセージの設定時に ERROR_CODE_NOT_AVAILABLE_IN_REGION
エラーコードを使用できます。
Kotlin
mediaSession.setPlaybackState( PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR) .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region)) // ...and any other setters. .build())
Java
mediaSession.setPlaybackState( new PlaybackStateCompat.Builder() .setState(PlaybackStateCompat.STATE_ERROR) .setErrorMessage(PlaybackStateCompat.ERROR_CODE_NOT_AVAILABLE_IN_REGION, getString(R.string.error_unsupported_region)) // ...and any other setters. .build());
エラー状態の詳細については、メディア セッションの使用: 状態とエラーをご覧ください。
Android Auto ユーザーがエラーを解決するためにスマートフォン アプリを開く必要がある場合は、メッセージ内でユーザーにその情報を提供します。たとえば、エラー メッセージは、「ログインしてください」ではなく、「[アプリ名] にログインしてください」とします。