public class

MediaBrowser

extends MediaController

 java.lang.Object

androidx.media2.MediaController

↳androidx.media2.MediaBrowser

Gradle dependencies

compile group: 'androidx.media2', name: 'media2', version: '1.0.0-alpha04'

  • groupId: androidx.media2
  • artifactId: media2
  • version: 1.0.0-alpha04

Artifact androidx.media2:media2:1.0.0-alpha04 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.media2:media2 com.android.support:media2

Overview

Browses media content offered by a MediaLibraryService.

Summary

Constructors
publicMediaBrowser(Context context, SessionToken token, java.util.concurrent.Executor executor, MediaBrowser.BrowserCallback callback)

Methods
public <any>getChildren(java.lang.String parentId, int page, int pageSize, MediaLibraryService.LibraryParams params)

Gets the list of children under the parent.

public <any>getItem(java.lang.String mediaId)

Gets the media item with the given media id.

public <any>getLibraryRoot(MediaLibraryService.LibraryParams params)

Gets the library root.

public <any>getSearchResult(java.lang.String query, int page, int pageSize, MediaLibraryService.LibraryParams params)

Gets the search result from lhe library service.

public <any>search(java.lang.String query, MediaLibraryService.LibraryParams params)

Sends a search request to the library service.

public <any>subscribe(java.lang.String parentId, MediaLibraryService.LibraryParams params)

Subscribes to a parent id for the change in its children.

public <any>unsubscribe(java.lang.String parentId)

Unsubscribes for changes to the children of the parent, which was previously subscribed with MediaBrowser.

from MediaControlleraddPlaylistItem, adjustVolume, close, fastForward, getBufferedPosition, getBufferingState, getConnectedSessionToken, getCurrentMediaItem, getCurrentMediaItemIndex, getCurrentPosition, getDuration, getNextMediaItemIndex, getPlaybackInfo, getPlaybackSpeed, getPlayerState, getPlaylist, getPlaylistMetadata, getPreviousMediaItemIndex, getRepeatMode, getSessionActivity, getShuffleMode, isConnected, pause, play, playFromMediaId, playFromSearch, playFromUri, prepare, prepareFromMediaId, prepareFromSearch, prepareFromUri, removePlaylistItem, replacePlaylistItem, rewind, seekTo, sendCustomCommand, setMediaItem, setPlaybackSpeed, setPlaylist, setRating, setRepeatMode, setShuffleMode, setTimeDiff, setVolumeTo, skipBackward, skipForward, skipToNextPlaylistItem, skipToPlaylistItem, skipToPreviousPlaylistItem, updatePlaylistMetadata
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public MediaBrowser(Context context, SessionToken token, java.util.concurrent.Executor executor, MediaBrowser.BrowserCallback callback)

Methods

public <any> getLibraryRoot(MediaLibraryService.LibraryParams params)

Gets the library root.

If it's successfully completed, MediaBrowser.BrowserResult.getMediaItem() will return the library root.

Parameters:

params: library params getting root

See also: MediaBrowser.BrowserResult.getMediaItem()

public <any> subscribe(java.lang.String parentId, MediaLibraryService.LibraryParams params)

Subscribes to a parent id for the change in its children. When there's a change, MediaBrowser.BrowserCallback will be called with the library params. You should call MediaBrowser to get the items under the parent.

Parameters:

parentId: non-empty parent id
params: library params

public <any> unsubscribe(java.lang.String parentId)

Unsubscribes for changes to the children of the parent, which was previously subscribed with MediaBrowser.

This unsubscribes all previous subscription with the parent id, regardless of the library param that was previously sent to the library service.

Parameters:

parentId: non-empty parent id

public <any> getChildren(java.lang.String parentId, int page, int pageSize, MediaLibraryService.LibraryParams params)

Gets the list of children under the parent.

If it's successfully completed, MediaBrowser.BrowserResult.getMediaItems() will return the list of children.

Parameters:

parentId: non-empty parent id for getting the children
page: page number to get the result. Starts from 0
pageSize: page size. Should be greater or equal to 1
params: library params

See also: MediaBrowser.BrowserResult.getMediaItems()

public <any> getItem(java.lang.String mediaId)

Gets the media item with the given media id.

If it's successfully completed, MediaBrowser.BrowserResult.getMediaItem() will return the media item.

Parameters:

mediaId: non-empty media id for specifying the item

See also: MediaBrowser.BrowserResult.getMediaItems()

public <any> search(java.lang.String query, MediaLibraryService.LibraryParams params)

Sends a search request to the library service.

Returned MediaBrowser.BrowserResult will only tell whether the attemp to search was successful. For getting the search result, waits for MediaBrowser.BrowserCallback the search result and calls MediaBrowser} for getting the result.

Parameters:

query: non-empty search query
params: library params

See also: MediaBrowser.BrowserCallback, MediaBrowser

public <any> getSearchResult(java.lang.String query, int page, int pageSize, MediaLibraryService.LibraryParams params)

Gets the search result from lhe library service.

If it's successfully completed, MediaBrowser.BrowserResult.getMediaItems() will return the search result.

Parameters:

query: non-empty search query that you've specified with MediaBrowser.
page: page number to get search result. Starts from 0
pageSize: page size. Should be greater or equal to 1
params: library params

See also: MediaBrowser.BrowserResult.getMediaItems()

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.media2;

import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;

import android.content.Context;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.concurrent.futures.ResolvableFuture;
import androidx.media2.MediaLibraryService.LibraryParams;
import androidx.media2.MediaLibraryService.LibraryResult;
import androidx.media2.MediaLibraryService.MediaLibrarySession;
import androidx.versionedparcelable.NonParcelField;
import androidx.versionedparcelable.ParcelField;

import com.google.common.util.concurrent.ListenableFuture;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.concurrent.Executor;

/**
 * Browses media content offered by a {@link MediaLibraryService}.
 */
public class MediaBrowser extends MediaController {
    static final String TAG = "MediaBrowser";
    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);

    /**
     * Callback to listen events from {@link MediaLibraryService}.
     */
    public static class BrowserCallback extends MediaController.ControllerCallback {
        /**
         * Called when there's change in the parent's children after you've subscribed to the parent
         * with {@link #subscribe}.
         * <p>
         * This API is called when the library service called
         * {@link MediaLibrarySession#notifyChildrenChanged} for the parent.
         *
         * @param browser the browser for this event
         * @param parentId non-empty parent id that you've specified with
         *                 {@link #subscribe(String, LibraryParams)}
         * @param itemCount number of children
         * @param params library params from the library service. Can be differ from params
         *               that you've specified with {@link #subscribe(String, LibraryParams)}.
         */
        public void onChildrenChanged(@NonNull MediaBrowser browser, @NonNull String parentId,
                @IntRange(from = 0) int itemCount, @Nullable LibraryParams params) { }

        /**
         * Called when there's change in the search result requested by the previous
         * {@link MediaBrowser#search(String, LibraryParams)}.
         *
         * @param browser the browser for this event
         * @param query non-empty search query that you've specified with
         *              {@link #search(String, LibraryParams)}
         * @param itemCount The item count for the search result
         * @param params library params from the library service. Can be differ from params
         *               that you've specified with {@link #search(String, LibraryParams)}.
         */
        public void onSearchResultChanged(@NonNull MediaBrowser browser, @NonNull String query,
                @IntRange(from = 0) int itemCount, @Nullable LibraryParams params) { }
    }

    public MediaBrowser(@NonNull Context context, @NonNull SessionToken token,
            @NonNull /*@CallbackExecutor*/ Executor executor, @NonNull BrowserCallback callback) {
        super(context, token, executor, callback);
    }

    @Override
    MediaBrowserImpl createImpl(@NonNull Context context, @NonNull SessionToken token,
            @NonNull Executor executor, @NonNull MediaController.ControllerCallback callback) {
        if (token.isLegacySession()) {
            return new MediaBrowserImplLegacy(
                    context, this, token, executor, (BrowserCallback) callback);
        } else {
            return new MediaBrowserImplBase(
                    context, this, token, executor, (BrowserCallback) callback);
        }
    }

    @Override
    MediaBrowserImpl getImpl() {
        return (MediaBrowserImpl) super.getImpl();
    }

    @Override
    BrowserCallback getCallback() {
        return (BrowserCallback) super.getCallback();
    }

    /**
     * Gets the library root.
     * <p>
     * If it's successfully completed, {@link BrowserResult#getMediaItem()} will return the library
     * root.
     *
     * @param params library params getting root
     * @see BrowserResult#getMediaItem()
     */
    @NonNull
    public ListenableFuture<BrowserResult> getLibraryRoot(@Nullable final LibraryParams params) {
        if (isConnected()) {
            return getImpl().getLibraryRoot(params);
        }
        return createDisconnectedFuture();
    }

    /**
     * Subscribes to a parent id for the change in its children. When there's a change,
     * {@link BrowserCallback#onChildrenChanged(MediaBrowser, String, int, LibraryParams)} will be
     * called with the library params. You should call
     * {@link #getChildren(String, int, int, LibraryParams)} to get the items under the parent.
     *
     * @param parentId non-empty parent id
     * @param params library params
     */
    public @NonNull ListenableFuture<BrowserResult> subscribe(@NonNull String parentId,
            @Nullable LibraryParams params) {
        if (TextUtils.isEmpty(parentId)) {
            throw new IllegalArgumentException("parentId shouldn't be empty");
        }
        if (isConnected()) {
            return getImpl().subscribe(parentId, params);
        }
        return createDisconnectedFuture();
    }

    /**
     * Unsubscribes for changes to the children of the parent, which was previously subscribed with
     * {@link #subscribe(String, LibraryParams)}.
     * <p>
     * This unsubscribes all previous subscription with the parent id, regardless of the library
     * param that was previously sent to the library service.
     *
     * @param parentId non-empty parent id
     */
    public @NonNull ListenableFuture<BrowserResult> unsubscribe(@NonNull String parentId) {
        if (TextUtils.isEmpty(parentId)) {
            throw new IllegalArgumentException("parentId shouldn't be empty");
        }
        if (isConnected()) {
            return getImpl().unsubscribe(parentId);
        }
        return createDisconnectedFuture();
    }

    /**
     * Gets the list of children under the parent.
     * <p>
     * If it's successfully completed, {@link BrowserResult#getMediaItems()} will return the list
     * of children.
     *
     * @param parentId non-empty parent id for getting the children
     * @param page page number to get the result. Starts from {@code 0}
     * @param pageSize page size. Should be greater or equal to {@code 1}
     * @param params library params
     * @see BrowserResult#getMediaItems()
     */
    public @NonNull ListenableFuture<BrowserResult> getChildren(@NonNull String parentId,
            @IntRange(from = 0) int page, @IntRange(from = 1) int pageSize,
            @Nullable LibraryParams params) {
        if (TextUtils.isEmpty(parentId)) {
            throw new IllegalArgumentException("parentId shouldn't be empty");
        }
        if (page < 0) {
            throw new IllegalArgumentException("page shouldn't be negative");
        }
        if (pageSize < 1) {
            throw new IllegalArgumentException("pageSize shouldn't be less than 1");
        }
        if (isConnected()) {
            return getImpl().getChildren(parentId, page, pageSize, params);
        }
        return createDisconnectedFuture();
    }

    /**
     * Gets the media item with the given media id.
     * <p>
     * If it's successfully completed, {@link BrowserResult#getMediaItem()} will return the media
     * item.
     *
     * @param mediaId non-empty media id for specifying the item
     * @see BrowserResult#getMediaItems()
     */
    public @NonNull ListenableFuture<BrowserResult> getItem(@NonNull final String mediaId) {
        if (TextUtils.isEmpty(mediaId)) {
            throw new IllegalArgumentException("mediaId shouldn't be empty");
        }
        if (isConnected()) {
            return getImpl().getItem(mediaId);
        }
        return createDisconnectedFuture();
    }

    /**
     * Sends a search request to the library service.
     * <p>
     * Returned {@link BrowserResult} will only tell whether the attemp to search was successful.
     * For getting the search result, waits for
     * {@link BrowserCallback#getSearchResult(String, int, int, LibraryParams)} the search result
     * and calls {@link #getSearchResult(String, int, int, LibraryParams)}} for getting the result.
     *
     * @param query non-empty search query
     * @param params library params
     * @see BrowserCallback#getSearchResult(String, int, int, LibraryParams)
     * @see #getSearchResult(String, int, int, LibraryParams)
     */
    public @NonNull ListenableFuture<BrowserResult> search(@NonNull String query,
            @Nullable LibraryParams params) {
        if (TextUtils.isEmpty(query)) {
            throw new IllegalArgumentException("query shouldn't be empty");
        }
        if (isConnected()) {
            return getImpl().search(query, params);
        }
        return createDisconnectedFuture();
    }

    /**
     * Gets the search result from lhe library service.
     * <p>
     * If it's successfully completed, {@link BrowserResult#getMediaItems()} will return the search
     * result.
     *
     * @param query non-empty search query that you've specified with
     *              {@link #search(String, LibraryParams)}.
     * @param page page number to get search result. Starts from {@code 0}
     * @param pageSize page size. Should be greater or equal to {@code 1}
     * @param params library params
     * @see BrowserResult#getMediaItems()
     */
    public @NonNull ListenableFuture<BrowserResult> getSearchResult(final @NonNull String query,
            @IntRange(from = 0) int page, @IntRange(from = 1) int pageSize,
            final @Nullable LibraryParams params) {
        if (TextUtils.isEmpty(query)) {
            throw new IllegalArgumentException("query shouldn't be empty");
        }
        if (page < 0) {
            throw new IllegalArgumentException("page shouldn't be negative");
        }
        if (pageSize < 1) {
            throw new IllegalArgumentException("pageSize shouldn't be less than 1");
        }
        if (isConnected()) {
            return getImpl().getSearchResult(query, page, pageSize, params);
        }
        return createDisconnectedFuture();
    }

    private static ListenableFuture<BrowserResult> createDisconnectedFuture() {
        return BrowserResult.createFutureWithResult(BrowserResult.RESULT_CODE_DISCONNECTED);
    }

    /**
     * Result class to be used with {@link ListenableFuture} for asynchronous calls.
     */
    // Specify full name to workaround build error 'cannot find symbol'
    @androidx.versionedparcelable.VersionedParcelize(isCustom = true)
    public static class BrowserResult extends androidx.versionedparcelable.CustomVersionedParcelable
            implements RemoteResult {
        /**
         * @hide
         */
        @IntDef(flag = false, /*prefix = "RESULT_CODE",*/ value = {
                RESULT_CODE_SUCCESS,
                RESULT_CODE_UNKNOWN_ERROR,
                RESULT_CODE_INVALID_STATE,
                RESULT_CODE_BAD_VALUE,
                RESULT_CODE_PERMISSION_DENIED,
                RESULT_CODE_IO_ERROR,
                RESULT_CODE_SKIPPED,
                RESULT_CODE_DISCONNECTED,
                RESULT_CODE_NOT_SUPPORTED,
                RESULT_CODE_AUTHENTICATION_EXPIRED,
                RESULT_CODE_PREMIUM_ACCOUNT_REQUIRED,
                RESULT_CODE_CONCURRENT_STREAM_LIMIT,
                RESULT_CODE_PARENTAL_CONTROL_RESTRICTED,
                RESULT_CODE_NOT_AVAILABLE_IN_REGION,
                RESULT_CODE_SKIP_LIMIT_REACHED,
                RESULT_CODE_SETUP_REQUIRED})
        @Retention(RetentionPolicy.SOURCE)
        @RestrictTo(LIBRARY_GROUP)
        public @interface ResultCode {}

        @ParcelField(1)
        int mResultCode;
        @ParcelField(2)
        long mCompletionTime;
        @ParcelField(3)
        MediaItem mItem;
        @ParcelField(4)
        LibraryParams mParams;
        // Mark list of media items NonParcelField to send the list through the ParcelImpListSlice.
        @NonParcelField
        List<MediaItem> mItemList;
        @ParcelField(5)
        ParcelImplListSlice mItemListSlice;

        // For versioned parcelable.
        BrowserResult() {
            // no-op
        }

        BrowserResult(@ResultCode int resultCode) {
            this(resultCode, null, null, null);
        }

        BrowserResult(@ResultCode int resultCode, @Nullable MediaItem item,
                @Nullable LibraryParams params) {
            this(resultCode, item, null, params);
        }

        BrowserResult(@ResultCode int resultCode, @Nullable List<MediaItem> items,
                @Nullable LibraryParams params) {
            this(resultCode, null, items, params);
        }

        BrowserResult(@ResultCode int resultCode, @Nullable MediaItem item,
                @Nullable List<MediaItem> items, @Nullable LibraryParams params) {
            this(resultCode, item, items, params, SystemClock.elapsedRealtime());
        }

        BrowserResult(@ResultCode int resultCode, @Nullable MediaItem item,
                @Nullable List<MediaItem> items, @Nullable LibraryParams params,
                long elapsedTime) {
            mResultCode = resultCode;
            mItem = item;
            mItemList = items;
            mParams = params;
            mCompletionTime = elapsedTime;
        }

        static ListenableFuture<BrowserResult> createFutureWithResult(@ResultCode int resultCode) {
            ResolvableFuture<BrowserResult> result = ResolvableFuture.create();
            result.set(new BrowserResult(resultCode));
            return result;
        }

        static BrowserResult from(@Nullable LibraryResult result) {
            if (result == null) {
                return null;
            }
            return new BrowserResult(result.getResultCode(), result.getMediaItem(),
                    result.getMediaItems(), result.getLibraryParams(), result.getCompletionTime());
        }

        /**
         * Gets the result code.
         *
         * @return result code
         * @see #RESULT_CODE_SUCCESS
         * @see #RESULT_CODE_UNKNOWN_ERROR
         * @see #RESULT_CODE_INVALID_STATE
         * @see #RESULT_CODE_BAD_VALUE
         * @see #RESULT_CODE_PERMISSION_DENIED
         * @see #RESULT_CODE_IO_ERROR
         * @see #RESULT_CODE_SKIPPED
         * @see #RESULT_CODE_DISCONNECTED
         * @see #RESULT_CODE_NOT_SUPPORTED
         * @see #RESULT_CODE_AUTHENTICATION_EXPIRED
         * @see #RESULT_CODE_PREMIUM_ACCOUNT_REQUIRED
         * @see #RESULT_CODE_CONCURRENT_STREAM_LIMIT
         * @see #RESULT_CODE_PARENTAL_CONTROL_RESTRICTED
         * @see #RESULT_CODE_NOT_AVAILABLE_IN_REGION
         * @see #RESULT_CODE_SKIP_LIMIT_REACHED
         * @see #RESULT_CODE_SETUP_REQUIRED
         */
        @Override
        public @ResultCode int getResultCode() {
            return mResultCode;
        }

        /**
         * Gets the completion time of the command. Being more specific, it's the same as
         * {@link android.os.SystemClock#elapsedRealtime()} when the command is completed.
         *
         * @return completion time of the command
         */
        @Override
        public long getCompletionTime() {
            return mCompletionTime;
        }

        /**
         * Gets the media item.
         * <p>
         * Can be {@code null} if an error happened or the command doesn't return a media item.
         *
         * @return media item
         * @see MediaBrowser#getLibraryRoot(LibraryParams)
         * @see MediaBrowser#getItem(String)
         */
        @Override
        public @Nullable MediaItem getMediaItem() {
            return mItem;
        }

        /**
         * Gets the list of media item.
         * <p>
         * Can be {@code null} if an error happened or the command doesn't return a list of media
         * items.
         *
         * @return list of media item
         * @see MediaBrowser#getSearchResult(String, int, int, LibraryParams)
         * @see MediaBrowser#getChildren(String, int, int, LibraryParams)
         **/
        public @Nullable List<MediaItem> getMediaItems() {
            return mItemList;
        }

        /**
         * Gets the library params
         *
         * @return library params.
         */
        public @Nullable LibraryParams getLibraryParams() {
            return mParams;
        }

        /**
         * @hide
         * @param isStream
         */
        @RestrictTo(LIBRARY)
        @Override
        public void onPreParceling(boolean isStream) {
            mItemListSlice = MediaUtils.convertMediaItemListToParcelImplListSlice(mItemList);
        }

        /**
         * @hide
         */
        @RestrictTo(LIBRARY)
        @Override
        public void onPostParceling() {
            mItemList = MediaUtils.convertParcelImplListSliceToMediaItemList(mItemListSlice);
            mItemListSlice = null;
        }
    }

    interface MediaBrowserImpl extends MediaControllerImpl {
        ListenableFuture<BrowserResult> getLibraryRoot(@Nullable LibraryParams rootHints);
        ListenableFuture<BrowserResult> subscribe(@NonNull String parentId,
                @Nullable LibraryParams params);
        ListenableFuture<BrowserResult> unsubscribe(@NonNull String parentId);
        ListenableFuture<BrowserResult> getChildren(@NonNull String parentId, int page,
                int pageSize, @Nullable LibraryParams params);
        ListenableFuture<BrowserResult> getItem(@NonNull String mediaId);
        ListenableFuture<BrowserResult> search(@NonNull String query,
                @Nullable LibraryParams params);
        ListenableFuture<BrowserResult> getSearchResult(@NonNull String query, int page,
                int pageSize, @Nullable LibraryParams params);
    }
}