カスタム ブラウズ アクションを実装する

カスタム再生操作を使用して再生ビューで独自の機能をサポートするのと同様に、カスタム ブラウズ アクションを使用してブラウジング ビューで独自の機能をサポートできます。たとえば、ユーザーがプレイリストをダウンロードしたり、アイテムをキューに追加したりできるように、カスタム ブラウズ アクションを使用できます。

OEM によって表示されるカスタム アクションよりも多くのカスタム アクションが存在する場合、オーバーフロー メニューがユーザーに表示されます。各カスタム ブラウズ アクションは以下で定義されます。

  • アクション ID: 一意の文字列識別子
  • アクション ラベル: ユーザーに表示されるテキスト
  • アクション アイコンの Uniform Resource Identifier(URI): 色合いを調整できるベクター型ドローアブル

カスタム ブラウズ アクションのオーバーフロー

図 1. カスタム ブラウズ アクションのオーバーフロー。

カスタム ブラウズ アクションのリストは、BrowseRoot の一部としてグローバルに定義します。定義したら、各 MediaItem にこれらのアクションのサブセットをアタッチします。

ユーザーがカスタム ブラウズ アクションを操作すると、アプリが onCustomAction でコールバックを受け取ります。その後、必要に応じて、MediaItem に対してアクションを処理し、アクション リストを更新します。これは、[Favorite]、[Download] などのステートフルなアクションに役立ちます。[Play Radio] など、更新が必要ないアクションでは、アクション リストを更新する必要はありません。

カスタム ブラウズ アクションのツールバー

図 2. カスタム ブラウズ アクションのツールバー。

ブラウズノードのルートにカスタム ブラウズ アクションをアタッチすることもできます。アタッチしたアクションは、メイン ツールバーの下のセカンダリ ツールバーに表示されます。

アプリにカスタム ブラウズ アクションを追加するには:

  1. MediaBrowserServiceCompat の実装で次の 2 つのメソッドをオーバーライドします。

  2. 実行時にアクションの上限を解析します。

    onGetRoot で、rootHints Bundle にキー BROWSER_ROOT_HINTS_KEY_CUSTOM_BROWSER_ACTION_LIMIT を使用して MediaItem ごとに許可されるアクションの上限数を取得します。上限 0 は、この機能がシステムでサポートされていないことを示します。

  3. カスタム ブラウズ アクションのグローバル リストを作成します。アクションごとに、次のキーを含む Bundle オブジェクトを作成します。

    • アクション ID EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID
    • アクション ラベル EXTRAS_KEY_CUSTOM_BROWSER_ACTION_LABEL
    • アクション アイコンの URI EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ICON_URI
  4. すべてのアクション Bundle オブジェクトをリストに追加します。

  5. グローバル リストを BrowseRoot に追加します。BrowseRoot のエクストラ Bundle で、キー BROWSER_SERVICE_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ROOT_LIST を使用して Parcelable ArrayList としてアクションのリストを追加します。

  6. MediaItem オブジェクトにアクションを追加します。各 MediaItem オブジェクトにアクションを追加するには、キー DESCRIPTION_EXTRAS_KEY_CUSTOM_BROWSER_ACTION_ID_LIST を使用して MediaDescriptionCompat エクストラにアクション ID のリストを含めます。このリストは、BrowseRoot で定義したアクションのグローバル リストのサブセットにする必要があります。

  7. アクションを処理し、進行状況または結果を返します。

    • onCustomAction で、アクション ID と必要なその他のデータに基づいてアクションを処理します。アクションをトリガーした MediaItem の ID は、キー EXTRAS_KEY_CUSTOM_BROWSER_ACTION_MEDIA_ITEM_ID を使用してエクストラから取得できます。

    • MediaItem に対するアクションのリストを更新するには、進行状況または結果バンドルにキー EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM を含めます。

アクションの状態を更新する

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>")
    

Parcelable 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 にアクションを追加する

MediaItem のブラウズ アクション ID は、onGetRoot で指定したブラウズ アクションのグローバル リストのサブセットにする必要があります。グローバル リストにないアクションは無視されます。

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 の結果を作成する

結果をビルドするには:

  1. 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);
                }
    
  2. 非同期の結果の場合は、result.detach で結果をデタッチします。

  3. 結果バンドルをビルドします。

    1. ユーザーにメッセージを表示します。

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_MESSAGE,
                    mContext.getString(stringRes))
      
    2. アイテムを更新する(アイテムでのアクションの更新に使用):

      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM, mediaId);
      
    3. 再生ビューを開きます。

      //Shows user the PBV without changing the playback state
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_SHOW_PLAYING_ITEM, null);
      
    4. ブラウズノードを更新します。

      //Change current browse node to mediaId
      mResultBundle.putString(EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_BROWSE_NODE, mediaId);
      
  4. 結果を確認します。

    • エラー: result.sendError(resultBundle) に電話する
    • 進行状況の更新: result.sendProgressUpdate(resultBundle) を呼び出す
    • 終了: result.sendResult(resultBundle) を呼び出す

アクションの状態を更新する

EXTRAS_KEY_CUSTOM_BROWSER_ACTION_RESULT_REFRESH_ITEM キーと result.sendProgressUpdate(resultBundle) メソッドを使用して、MediaItem を更新し、アクションの新しい状態を反映できます。これにより、アクションの進行状況と結果に関するリアルタイムのフィードバックをユーザーに提供できます。

ダウンロード アクションのサンプル

この例では、この機能を使用して 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% のダウンロード状態を示すアイコンを使用して、より詳しい情報を追加することもできます。

お気に入りのアクションのサンプル

もう一つの例は、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 プロジェクトをご覧ください。