Google は、黒人コミュニティに対する人種平等の促進に取り組んでいます。取り組みを見る

新しいメディア コントロール

Android 11 では、MediaSessionMediaRouter2 API を使用してコントロールと音声出力情報が表示されるように、メディア コントロールの表示方法が更新されています。

Android 11 のメディア コントロールは、クイック設定の近くに配置されています。複数のアプリからのセッションは、スワイプ可能なカルーセルに配列されます。カルーセルには、セッションが次の順序で表示されます。

  • スマートフォンでローカルに再生されるストリーム
  • リモート ストリーム(外部デバイスやキャスト セッションで検出されたストリームなど)
  • 以前の再開可能なセッション(最後に再生された順)

ユーザーは、アプリを起動しなくてもカルーセルから以前のセッションを再開できます。再生が開始されると、ユーザーは通常の方法でメディア コントロールを操作できます。

再生の再開のサポート

この機能を使用するには、[開発者向けオプション] 設定で [メディアの再開] を有効にします。

クイック設定領域にプレーヤー アプリが表示されるようにするには、有効な MediaSession トークンを使用して MediaStyle 通知を作成する必要があります。

メディア プレーヤーのブランド アイコンを表示するには、NotificationBuilder.setSmallIcon() を使用します。

再生の再開をサポートするには、アプリに MediaBrowserServiceMediaSession を実装する必要があります。

MediaBrowserService の実装

デバイスが起動すると、システムは最近使用された 5 つのメディアアプリを特定し、各アプリから再生を再開するためのコントロールを提供します。

システムは SystemUI 経由の接続によって MediaBrowserService へのアクセスを試みます。アプリでは、そのような接続を許可しなければなりません。許可しない場合、再生の再開はサポートされません。

SystemUI 経由の接続は、パッケージ名 com.android.systemui と署名によって検出し、確認できます。SystemUI はプラットフォーム署名によって署名されます。プラットフォーム署名に従ってチェックを行う方法の例については、UAMP アプリを確認してください。

再生の再開をサポートするには、MediaBrowserService に次の動作を実装する必要があります。

  • onGetRoot() は null 以外のルートをすばやく返す必要があります。その他の複雑なロジックは onLoadChildren() が処理するようにします。

  • ルートのメディア ID で onLoadChildren() を呼び出した場合、その結果には、子である FLAG_PLAYABLE が含まれていなければなりません。

  • MediaBrowserService は、EXTRA_RECENT クエリを受け取ったときに、直近に再生されたメディア アイテムを返す必要があります。返される値は、汎用的な関数ではなく、実際のメディア アイテムでなければなりません。

  • MediaBrowserService は、タイトルサブタイトルが空でない、適切な MediaDescription を指定する必要があります。またアイコンの URI またはアイコンのビットマップも設定します。

以下のコード例は、onGetRoot() の実装方法を示しています。

Kotlin

override fun onGetRoot(
    clientPackageName: String,
    clientUid: Int,
    rootHints: Bundle?
): BrowserRoot? {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        rootHints?.let {
            if (it.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return BrowserRoot(MY_RECENTS_ROOT_ID, null)
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return BrowserRoot(MY_MEDIA_ROOT_ID, null)
    }
    // Return an empty tree to disallow browsing.
    return BrowserRoot(MY_EMPTY_ROOT_ID, null)

Java

@Override
public BrowserRoot onGetRoot(String clientPackageName, int clientUid,
    Bundle rootHints) {
    ...
    // Verify that the specified package is SystemUI. You'll need to write your
    // own logic to do this.
    if (isSystem(clientPackageName, clientUid)) {
        if (rootHints != null) {
            if (rootHints.getBoolean(BrowserRoot.EXTRA_RECENT)) {
                // Return a tree with a single playable media item for resumption.
                return new BrowserRoot(MY_RECENTS_ROOT_ID, null);
            }
        }
        // You can return your normal tree if the EXTRA_RECENT flag is not present.
        return new BrowserRoot(MY_MEDIA_ROOT_ID, null);
    }
    // Return an empty tree to disallow browsing.
    return new BrowserRoot(MY_EMPTY_ROOT_ID, null);
}

MediaSession の実装

システムが MediaSessionMediaMetadata から以下の情報を取得して表示します。

  • METADATA_KEY_ALBUM_ART_URI
  • METADATA_KEY_TITLE
  • METADATA_KEY_ARTIST
  • METADATA_KEY_DURATION(所要時間が設定されていない場合は、シークバーに進行状況が表示されません)

再生の再開を可能にするには、MediaSessiononPlay() に対する MediaSession コールバックを実装する必要があります。

メディア プレーヤーには、現在再生中のメディアの経過時間と、MediaSession PlaybackState にマッピングされたシークバーが表示されます。

シークバーが正しく機能するには、PlaybackState.Builder#setActions を実装して ACTION_SEEK_TO を含める必要があります。これを行わない場合、プレーヤーには経過時間と所要時間だけが表示されます。

プレーヤー コントロールを設定するには、Notification.Builder#setCustomActions を使用します。クイック設定を折りたたんだ場合、メディア プレーヤーには Notification.MediaStyle#setShowsActionsInCompactView で示されたアクションだけが表示されます。