Merge "Add getMediaItem API to MediaBrowser"

This commit is contained in:
RoboErik
2015-01-28 18:52:39 +00:00
committed by Android (Google) Code Review
4 changed files with 171 additions and 21 deletions

View File

@@ -16217,6 +16217,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();
@@ -16246,6 +16247,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>);
@@ -27360,6 +27367,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);

View File

@@ -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.
*/

View File

@@ -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);
}

View File

@@ -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) {