Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b1c88103 authored by RoboErik's avatar RoboErik
Browse files

Add getMediaItem API to MediaBrowser

This adds all the plumbing for supporting a getMediaItem call in
MediaBrowser.

Will also need to add a support lib component to make it backward
compatible.

Change-Id: I528e9ebaf4e0fe386f346ef85c14973168a380df
parent adf1c93f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -16160,6 +16160,7 @@ package android.media.browse {
    method public void connect();
    method public void disconnect();
    method public android.os.Bundle getExtras();
    method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
    method public java.lang.String getRoot();
    method public android.content.ComponentName getServiceComponent();
    method public android.media.session.MediaSession.Token getSessionToken();
@@ -16189,6 +16190,12 @@ package android.media.browse {
    field public static final int FLAG_PLAYABLE = 2; // 0x2
  }
  public static abstract class MediaBrowser.MediaItemCallback {
    ctor public MediaBrowser.MediaItemCallback();
    method public void onError();
    method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
  }
  public static abstract class MediaBrowser.SubscriptionCallback {
    ctor public MediaBrowser.SubscriptionCallback();
    method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -27268,6 +27275,7 @@ package android.service.media {
  public abstract class MediaBrowserService extends android.app.Service {
    ctor public MediaBrowserService();
    method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
    method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
    method public android.media.session.MediaSession.Token getSessionToken();
    method public void notifyChildrenChanged(java.lang.String);
    method public android.os.IBinder onBind(android.content.Intent);
+78 −2
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.MediaBrowserService;
import android.service.media.IMediaBrowserService;
import android.service.media.IMediaBrowserServiceCallbacks;
@@ -347,8 +348,8 @@ public final class MediaBrowser {
     */
    public void unsubscribe(@NonNull String parentId) {
        // Check arguments.
        if (parentId == null) {
            throw new IllegalArgumentException("parentId is null");
        if (TextUtils.isEmpty(parentId)) {
            throw new IllegalArgumentException("parentId is empty.");
        }

        // Remove from our list.
@@ -366,6 +367,60 @@ public final class MediaBrowser {
        }
    }

    /**
     * Retrieves a specific {@link MediaItem} from the connected service. Not
     * all services may support this, so falling back to subscribing to the
     * parent's id should be used when unavailable.
     *
     * @param mediaId The id of the item to retrieve.
     * @param cb The callback to receive the result on.
     */
    public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
        if (TextUtils.isEmpty(mediaId)) {
            throw new IllegalArgumentException("mediaId is empty.");
        }
        if (cb == null) {
            throw new IllegalArgumentException("cb is null.");
        }
        if (mState != CONNECT_STATE_CONNECTED) {
            Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onError();
                }
            });
            return;
        }
        ResultReceiver receiver = new ResultReceiver(mHandler) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
                if (resultCode != 0 || resultData == null
                        || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
                    cb.onError();
                    return;
                }
                Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
                if (!(item instanceof MediaItem)) {
                    cb.onError();
                }
                cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
                        MediaBrowserService.KEY_MEDIA_ITEM));
            }
        };
        try {
            mServiceBinder.getMediaItem(mediaId, receiver);
        } catch (RemoteException e) {
            Log.i(TAG, "Remote error getting media item.");
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    cb.onError();
                }
            });
        }
    }

    /**
     * For debugging.
     */
@@ -689,6 +744,27 @@ public final class MediaBrowser {
        }
    }

    /**
     * Callback for receiving the result of {@link #getMediaItem}.
     */
    public static abstract class MediaItemCallback {

        /**
         * Called when the item has been returned by the browser service.
         *
         * @param item The item that was returned or null if it doesn't exist.
         */
        public void onMediaItemLoaded(MediaItem item) {
        }

        /**
         * Called when the id doesn't exist or there was an error retrieving the
         * item.
         */
        public void onError() {
        }
    }

    /**
     * ServiceConnection to the other app.
     */
+2 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@ import android.content.res.Configuration;
import android.service.media.IMediaBrowserServiceCallbacks;
import android.net.Uri;
import android.os.Bundle;
import android.os.ResultReceiver;

/**
 * Media API allows clients to browse through hierarchy of a user’s media collection,
@@ -18,4 +19,5 @@ oneway interface IMediaBrowserService {

    void addSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
    void removeSubscription(String uri, IMediaBrowserServiceCallbacks callbacks);
    void getMediaItem(String uri, in ResultReceiver cb);
}
 No newline at end of file
+83 −19
Original line number Diff line number Diff line
@@ -32,8 +32,10 @@ import android.os.Bundle;
import android.os.IBinder;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.service.media.IMediaBrowserService;
import android.service.media.IMediaBrowserServiceCallbacks;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;

@@ -74,6 +76,13 @@ public abstract class MediaBrowserService extends Service {
    @SdkConstant(SdkConstantType.SERVICE_ACTION)
    public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";

    /**
     * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
     *
     * @hide
     */
    public static final String KEY_MEDIA_ITEM = "media_item";

    private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap();
    private final Handler mHandler = new Handler();
    private ServiceBinder mBinder;
@@ -261,6 +270,33 @@ public abstract class MediaBrowserService extends Service {
                }
            });
        }

        @Override
        public void getMediaItem(final String mediaId, final ResultReceiver receiver) {
            if (TextUtils.isEmpty(mediaId) || receiver == null) {
                return;
            }

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    final Result<MediaBrowser.MediaItem> result
                            = new Result<MediaBrowser.MediaItem>(mediaId) {
                        @Override
                        void onResultSent(MediaBrowser.MediaItem item) {
                            Bundle bundle = new Bundle();
                            bundle.putParcelable(KEY_MEDIA_ITEM, item);
                            receiver.send(0, bundle);
                        }
                    };
                    try {
                        MediaBrowserService.this.getMediaItem(mediaId, result);
                    } catch (UnsupportedOperationException e) {
                        receiver.send(-1, null);
                    }
                }
            });
        }
    }

    @Override
@@ -284,20 +320,21 @@ public abstract class MediaBrowserService extends Service {
    /**
     * Called to get the root information for browsing by a particular client.
     * <p>
     * The implementation should verify that the client package has
     * permission to access browse media information before returning
     * the root id; it should return null if the client is not
     * allowed to access this information.
     * The implementation should verify that the client package has permission
     * to access browse media information before returning the root id; it
     * should return null if the client is not allowed to access this
     * information.
     * </p>
     *
     * @param clientPackageName The package name of the application
     * which is requesting access to browse media.
     * @param clientUid The uid of the application which is requesting
     * access to browse media.
     * @param clientPackageName The package name of the application which is
     *            requesting access to browse media.
     * @param clientUid The uid of the application which is requesting access to
     *            browse media.
     * @param rootHints An optional bundle of service-specific arguments to send
     * to the media browse service when connecting and retrieving the root id
     * for browsing, or null if none.  The contents of this bundle may affect
     * the information returned when browsing.
     *            to the media browse service when connecting and retrieving the
     *            root id for browsing, or null if none. The contents of this
     *            bundle may affect the information returned when browsing.
     * @return The {@link BrowserRoot} for accessing this app's content or null.
     */
    public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
            int clientUid, @Nullable Bundle rootHints);
@@ -305,24 +342,51 @@ public abstract class MediaBrowserService extends Service {
    /**
     * Called to get information about the children of a media item.
     * <p>
     * Implementations must call result.{@link Result#sendResult result.sendResult} with the list
     * of children. If loading the children will be an expensive operation that should be performed
     * on another thread, result.{@link Result#detach result.detach} may be called before returning
     * from this function, and then {@link Result#sendResult result.sendResult} called when
     * the loading is complete.
     * Implementations must call {@link Result#sendResult result.sendResult}
     * with the list of children. If loading the children will be an expensive
     * operation that should be performed on another thread,
     * {@link Result#detach result.detach} may be called before returning from
     * this function, and then {@link Result#sendResult result.sendResult}
     * called when the loading is complete.
     *
     * @param parentId The id of the parent media item whose
     * children are to be queried.
     * @return The list of children, or null if the id is invalid.
     * @param parentId The id of the parent media item whose children are to be
     *            queried.
     * @param result The Result to send the list of children to, or null if the
     *            id is invalid.
     */
    public abstract void onLoadChildren(@NonNull String parentId,
            @NonNull Result<List<MediaBrowser.MediaItem>> result);

    /**
     * Called to get a specific media item. The mediaId should be the same id
     * that would be returned for this item when it is in a list of child items.
     * <p>
     * Implementations must call {@link Result#sendResult result.sendResult}. If
     * loading the item will be an expensive operation {@link Result#detach
     * result.detach} may be called before returning from this function, and
     * then {@link Result#sendResult result.sendResult} called when the item has
     * been loaded.
     * <p>
     * The default implementation throws an exception.
     *
     * @param mediaId The id for the specific
     *            {@link android.media.browse.MediaBrowser.MediaItem}.
     * @param result The Result to send the item to, or null if the id is
     *            invalid.
     * @throws UnsupportedOperationException
     */
    public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
            throws UnsupportedOperationException {
        throw new UnsupportedOperationException("getMediaItem is not supported.");
    }

    /**
     * Call to set the media session.
     * <p>
     * This should be called as soon as possible during the service's startup.
     * It may only be called once.
     *
     * @param token The token for the service's {@link MediaSession}.
     */
    public void setSessionToken(final MediaSession.Token token) {
        if (token == null) {