OSDN Git Service

Update to MediaBrowser APIs per council feedback
authorRoboErik <epastern@google.com>
Wed, 27 Aug 2014 23:03:19 +0000 (16:03 -0700)
committerErik Pasternak <roboerik@android.com>
Thu, 28 Aug 2014 21:11:22 +0000 (21:11 +0000)
Does all the updates in the bug except the loadIcon/loadBitmap
methods, which are removed per feedback from Sharkey.

bug:17205016
Change-Id: Ie84d4d25a59c6985ce16972c26c8d1e5c02ff5c9

18 files changed:
Android.mk
api/current.txt
media/java/android/media/MediaDescription.aidl [new file with mode: 0644]
media/java/android/media/MediaDescription.java [new file with mode: 0644]
media/java/android/media/MediaMetadata.java
media/java/android/media/browse/MediaBrowser.java
media/java/android/media/browse/MediaBrowserItem.java [deleted file]
media/java/android/media/session/ISessionCallback.aidl
media/java/android/media/session/ISessionController.aidl
media/java/android/media/session/MediaController.java
media/java/android/media/session/MediaSession.aidl
media/java/android/media/session/MediaSession.java
media/java/android/media/session/PlaybackState.java
media/java/android/service/media/IMediaBrowserService.aidl [moved from media/java/android/media/browse/IMediaBrowserService.aidl with 76% similarity]
media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl [moved from media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl with 92% similarity]
media/java/android/service/media/MediaBrowserService.java [moved from media/java/android/media/browse/MediaBrowserService.java with 81% similarity]
services/core/java/com/android/server/media/MediaSessionRecord.java
tests/OneMedia/src/com/android/onemedia/NotificationHelper.java

index 3edaefc..35bb66c 100644 (file)
@@ -325,8 +325,6 @@ LOCAL_SRC_FILES += \
        media/java/android/media/IRemoteVolumeObserver.aidl \
        media/java/android/media/IRingtonePlayer.aidl \
        media/java/android/media/IVolumeController.aidl \
-       media/java/android/media/browse/IMediaBrowserService.aidl \
-       media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl \
        media/java/android/media/projection/IMediaProjection.aidl \
        media/java/android/media/projection/IMediaProjectionCallback.aidl \
        media/java/android/media/projection/IMediaProjectionManager.aidl \
@@ -346,6 +344,8 @@ LOCAL_SRC_FILES += \
        media/java/android/media/tv/ITvInputServiceCallback.aidl \
        media/java/android/media/tv/ITvInputSession.aidl \
        media/java/android/media/tv/ITvInputSessionCallback.aidl \
+       media/java/android/service/media/IMediaBrowserService.aidl \
+       media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl \
        telecomm/java/com/android/internal/telecomm/IVideoCallback.aidl \
        telecomm/java/com/android/internal/telecomm/IVideoProvider.aidl \
        telecomm/java/com/android/internal/telecomm/IConnectionService.aidl \
index 8a03269..829601d 100644 (file)
@@ -14920,6 +14920,31 @@ package android.media {
     ctor public MediaCryptoException(java.lang.String);
   }
 
+  public class MediaDescription implements android.os.Parcelable {
+    method public int describeContents();
+    method public java.lang.CharSequence getDescription();
+    method public android.os.Bundle getExtras();
+    method public android.graphics.Bitmap getIconBitmap();
+    method public android.net.Uri getIconUri();
+    method public java.lang.String getMediaId();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator CREATOR;
+  }
+
+  public static class MediaDescription.Builder {
+    ctor public MediaDescription.Builder();
+    method public android.media.MediaDescription build();
+    method public android.media.MediaDescription.Builder setDescription(java.lang.CharSequence);
+    method public android.media.MediaDescription.Builder setExtras(android.os.Bundle);
+    method public android.media.MediaDescription.Builder setIconBitmap(android.graphics.Bitmap);
+    method public android.media.MediaDescription.Builder setIconUri(android.net.Uri);
+    method public android.media.MediaDescription.Builder setMediaId(java.lang.String);
+    method public android.media.MediaDescription.Builder setSubtitle(java.lang.CharSequence);
+    method public android.media.MediaDescription.Builder setTitle(java.lang.CharSequence);
+  }
+
   public final class MediaDrm {
     ctor public MediaDrm(java.util.UUID) throws android.media.UnsupportedSchemeException;
     method public void closeSession(byte[]);
@@ -15098,7 +15123,7 @@ package android.media {
     method public boolean containsKey(java.lang.String);
     method public int describeContents();
     method public android.graphics.Bitmap getBitmap(java.lang.String);
-    method public android.media.MediaMetadata.Description getDescription();
+    method public android.media.MediaDescription getDescription();
     method public long getLong(java.lang.String);
     method public android.media.Rating getRating(java.lang.String);
     method public java.lang.String getString(java.lang.String);
@@ -15126,6 +15151,7 @@ package android.media {
     field public static final java.lang.String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
     field public static final java.lang.String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
     field public static final java.lang.String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
+    field public static final java.lang.String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
     field public static final java.lang.String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
     field public static final java.lang.String METADATA_KEY_RATING = "android.media.metadata.RATING";
     field public static final java.lang.String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
@@ -15146,14 +15172,6 @@ package android.media {
     method public android.media.MediaMetadata.Builder putText(java.lang.String, java.lang.CharSequence);
   }
 
-  public final class MediaMetadata.Description {
-    method public java.lang.CharSequence getDescription();
-    method public android.graphics.Bitmap getIcon();
-    method public android.net.Uri getIconUri();
-    method public java.lang.CharSequence getSubtitle();
-    method public java.lang.CharSequence getTitle();
-  }
-
   public abstract deprecated class MediaMetadataEditor {
     method public synchronized void addEditableKey(int);
     method public abstract void apply();
@@ -16239,7 +16257,6 @@ package android.media.browse {
     method public android.content.ComponentName getServiceComponent();
     method public android.media.session.MediaSession.Token getSessionToken();
     method public boolean isConnected();
-    method public void loadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowser.IconCallback);
     method public void subscribe(android.net.Uri, android.media.browse.MediaBrowser.SubscriptionCallback);
     method public void unsubscribe(android.net.Uri);
   }
@@ -16251,27 +16268,12 @@ package android.media.browse {
     method public void onConnectionSuspended();
   }
 
-  public static abstract class MediaBrowser.IconCallback {
-    ctor public MediaBrowser.IconCallback();
-    method public void onError(android.net.Uri);
-    method public void onIconLoaded(android.net.Uri, android.graphics.Bitmap);
-  }
-
-  public static abstract class MediaBrowser.SubscriptionCallback {
-    ctor public MediaBrowser.SubscriptionCallback();
-    method public void onChildrenLoaded(android.net.Uri, java.util.List<android.media.browse.MediaBrowserItem>);
-    method public void onError(android.net.Uri);
-  }
-
-  public final class MediaBrowserItem implements android.os.Parcelable {
+  public static class MediaBrowser.MediaItem implements android.os.Parcelable {
+    ctor public MediaBrowser.MediaItem(int, android.media.MediaDescription);
     method public int describeContents();
-    method public android.os.Bundle getExtras();
+    method public android.media.MediaDescription getDescription();
     method public int getFlags();
-    method public int getIconResourceId();
-    method public android.net.Uri getIconUri();
-    method public java.lang.CharSequence getSummary();
-    method public java.lang.CharSequence getTitle();
-    method public android.net.Uri getUri();
+    method public java.lang.String getMediaId();
     method public boolean isBrowsable();
     method public boolean isPlayable();
     method public void writeToParcel(android.os.Parcel, int);
@@ -16280,37 +16282,10 @@ package android.media.browse {
     field public static final int FLAG_PLAYABLE = 2; // 0x2
   }
 
-  public static final class MediaBrowserItem.Builder {
-    ctor public MediaBrowserItem.Builder(android.net.Uri, int, java.lang.CharSequence);
-    method public android.media.browse.MediaBrowserItem build();
-    method public android.media.browse.MediaBrowserItem.Builder setExtras(android.os.Bundle);
-    method public android.media.browse.MediaBrowserItem.Builder setIconResourceId(int);
-    method public android.media.browse.MediaBrowserItem.Builder setIconUri(android.net.Uri);
-    method public android.media.browse.MediaBrowserItem.Builder setSummary(java.lang.CharSequence);
-  }
-
-  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 android.media.session.MediaSession.Token getSessionToken();
-    method public void notifyChildrenChanged(android.net.Uri);
-    method public android.os.IBinder onBind(android.content.Intent);
-    method public abstract android.media.browse.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
-    method public abstract void onLoadChildren(android.net.Uri, android.media.browse.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowserItem>>);
-    method public abstract void onLoadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowserService.Result<android.graphics.Bitmap>);
-    method public void setSessionToken(android.media.session.MediaSession.Token);
-    field public static final java.lang.String SERVICE_ACTION = "android.media.browse.MediaBrowserService";
-  }
-
-  public static final class MediaBrowserService.BrowserRoot {
-    ctor public MediaBrowserService.BrowserRoot(android.net.Uri, android.os.Bundle);
-    method public android.os.Bundle getExtras();
-    method public android.net.Uri getRootUri();
-  }
-
-  public class MediaBrowserService.Result {
-    method public void detach();
-    method public void sendResult(T);
+  public static abstract class MediaBrowser.SubscriptionCallback {
+    ctor public MediaBrowser.SubscriptionCallback();
+    method public void onChildrenLoaded(android.net.Uri, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
+    method public void onError(android.net.Uri);
   }
 
 }
@@ -16405,7 +16380,7 @@ package android.media.session {
     method public java.lang.String getPackageName();
     method public android.media.session.MediaController.PlaybackInfo getPlaybackInfo();
     method public android.media.session.PlaybackState getPlaybackState();
-    method public java.util.List<android.media.session.MediaSession.Item> getQueue();
+    method public java.util.List<android.media.session.MediaSession.QueueItem> getQueue();
     method public java.lang.CharSequence getQueueTitle();
     method public int getRatingType();
     method public android.app.PendingIntent getSessionActivity();
@@ -16422,7 +16397,7 @@ package android.media.session {
     method public void onExtrasChanged(android.os.Bundle);
     method public void onMetadataChanged(android.media.MediaMetadata);
     method public void onPlaybackStateChanged(android.media.session.PlaybackState);
-    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.Item>);
+    method public void onQueueChanged(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void onQueueTitleChanged(java.lang.CharSequence);
     method public void onSessionDestroyed();
     method public void onSessionEvent(java.lang.String, android.os.Bundle);
@@ -16442,16 +16417,16 @@ package android.media.session {
     method public void fastForward();
     method public void pause();
     method public void play();
+    method public void playFromMediaId(java.lang.String, android.os.Bundle);
     method public void playFromSearch(java.lang.String, android.os.Bundle);
-    method public void playUri(android.net.Uri, android.os.Bundle);
     method public void rewind();
     method public void seekTo(long);
     method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle);
     method public void sendCustomAction(java.lang.String, android.os.Bundle);
     method public void setRating(android.media.Rating);
-    method public void skipToItem(long);
     method public void skipToNext();
     method public void skipToPrevious();
+    method public void skipToQueueItem(long);
     method public void stop();
   }
 
@@ -16472,7 +16447,7 @@ package android.media.session {
     method public void setPlaybackState(android.media.session.PlaybackState);
     method public void setPlaybackToLocal(android.media.AudioAttributes);
     method public void setPlaybackToRemote(android.media.VolumeProvider);
-    method public void setQueue(java.util.List<android.media.session.MediaSession.Item>);
+    method public void setQueue(java.util.List<android.media.session.MediaSession.QueueItem>);
     method public void setQueueTitle(java.lang.CharSequence);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
@@ -16487,34 +16462,27 @@ package android.media.session {
     method public boolean onMediaButtonEvent(android.content.Intent);
     method public void onPause();
     method public void onPlay();
+    method public void onPlayFromMediaId(java.lang.String, android.os.Bundle);
     method public void onPlayFromSearch(java.lang.String, android.os.Bundle);
-    method public void onPlayUri(android.net.Uri, android.os.Bundle);
     method public void onRewind();
     method public void onSeekTo(long);
     method public void onSetRating(android.media.Rating);
-    method public void onSkipToItem(long);
     method public void onSkipToNext();
     method public void onSkipToPrevious();
+    method public void onSkipToQueueItem(long);
     method public void onStop();
   }
 
-  public static final class MediaSession.Item implements android.os.Parcelable {
+  public static final class MediaSession.QueueItem implements android.os.Parcelable {
+    ctor public MediaSession.QueueItem(android.media.MediaDescription, long);
     method public int describeContents();
-    method public android.os.Bundle getExtras();
-    method public long getId();
-    method public android.media.MediaMetadata getMetadata();
-    method public android.net.Uri getUri();
+    method public android.media.MediaDescription getDescription();
+    method public long getQueueId();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final int UNKNOWN_ID = -1; // 0xffffffff
   }
 
-  public static final class MediaSession.Item.Builder {
-    ctor public MediaSession.Item.Builder(android.media.MediaMetadata, long, android.net.Uri);
-    method public android.media.session.MediaSession.Item build();
-    method public android.media.session.MediaSession.Item.Builder setExtras(android.os.Bundle);
-  }
-
   public static final class MediaSession.Token implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
@@ -16535,6 +16503,7 @@ package android.media.session {
   public final class PlaybackState implements android.os.Parcelable {
     method public int describeContents();
     method public long getActions();
+    method public long getActiveQueueItemId();
     method public long getBufferedPosition();
     method public java.util.List<android.media.session.PlaybackState.CustomAction> getCustomActions();
     method public java.lang.CharSequence getErrorMessage();
@@ -16546,15 +16515,15 @@ package android.media.session {
     field public static final long ACTION_FAST_FORWARD = 64L; // 0x40L
     field public static final long ACTION_PAUSE = 2L; // 0x2L
     field public static final long ACTION_PLAY = 4L; // 0x4L
+    field public static final long ACTION_PLAY_FROM_MEDIA_ID = 1024L; // 0x400L
     field public static final long ACTION_PLAY_FROM_SEARCH = 2048L; // 0x800L
     field public static final long ACTION_PLAY_PAUSE = 512L; // 0x200L
-    field public static final long ACTION_PLAY_URI = 1024L; // 0x400L
     field public static final long ACTION_REWIND = 8L; // 0x8L
     field public static final long ACTION_SEEK_TO = 256L; // 0x100L
     field public static final long ACTION_SET_RATING = 128L; // 0x80L
-    field public static final long ACTION_SKIP_TO_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L
     field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L
+    field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator CREATOR;
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
@@ -16568,6 +16537,7 @@ package android.media.session {
     field public static final int STATE_REWINDING = 5; // 0x5
     field public static final int STATE_SKIPPING_TO_NEXT = 10; // 0xa
     field public static final int STATE_SKIPPING_TO_PREVIOUS = 9; // 0x9
+    field public static final int STATE_SKIPPING_TO_QUEUE_ITEM = 11; // 0xb
     field public static final int STATE_STOPPED = 1; // 0x1
   }
 
@@ -16578,7 +16548,7 @@ package android.media.session {
     method public android.media.session.PlaybackState.Builder addCustomAction(android.media.session.PlaybackState.CustomAction);
     method public android.media.session.PlaybackState build();
     method public android.media.session.PlaybackState.Builder setActions(long);
-    method public android.media.session.PlaybackState.Builder setActiveItem(long);
+    method public android.media.session.PlaybackState.Builder setActiveQueueItemId(long);
     method public android.media.session.PlaybackState.Builder setBufferedPosition(long);
     method public android.media.session.PlaybackState.Builder setErrorMessage(java.lang.CharSequence);
     method public android.media.session.PlaybackState.Builder setState(int, long, float, long);
@@ -27094,6 +27064,33 @@ package android.service.dreams {
 
 }
 
+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 android.media.session.MediaSession.Token getSessionToken();
+    method public void notifyChildrenChanged(android.net.Uri);
+    method public android.os.IBinder onBind(android.content.Intent);
+    method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
+    method public abstract void onLoadChildren(android.net.Uri, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+    method public void setSessionToken(android.media.session.MediaSession.Token);
+    field public static final java.lang.String SERVICE_ACTION = "android.media.browse.MediaBrowserService";
+  }
+
+  public static final class MediaBrowserService.BrowserRoot {
+    ctor public MediaBrowserService.BrowserRoot(android.net.Uri, android.os.Bundle);
+    method public android.os.Bundle getExtras();
+    method public android.net.Uri getRootUri();
+  }
+
+  public class MediaBrowserService.Result {
+    method public void detach();
+    method public void sendResult(T);
+  }
+
+}
+
 package android.service.notification {
 
   public abstract class NotificationListenerService extends android.app.Service {
diff --git a/media/java/android/media/MediaDescription.aidl b/media/java/android/media/MediaDescription.aidl
new file mode 100644 (file)
index 0000000..6f934f7
--- /dev/null
@@ -0,0 +1,18 @@
+/* Copyright 2014, 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 android.media;
+
+parcelable MediaDescription;
diff --git a/media/java/android/media/MediaDescription.java b/media/java/android/media/MediaDescription.java
new file mode 100644 (file)
index 0000000..4399c0d
--- /dev/null
@@ -0,0 +1,276 @@
+package android.media;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ContentResolver;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Point;
+import android.graphics.RectF;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Size;
+
+/**
+ * A simple set of metadata for a media item suitable for display. This can be
+ * created using the Builder or retrieved from existing metadata using
+ * {@link MediaMetadata#getDescription()}.
+ */
+public class MediaDescription implements Parcelable {
+    /**
+     * A unique persistent id for the content or null.
+     */
+    private final String mMediaId;
+    /**
+     * A primary title suitable for display or null.
+     */
+    private final CharSequence mTitle;
+    /**
+     * A subtitle suitable for display or null.
+     */
+    private final CharSequence mSubtitle;
+    /**
+     * A description suitable for display or null.
+     */
+    private final CharSequence mDescription;
+    /**
+     * A bitmap icon suitable for display or null.
+     */
+    private final Bitmap mIcon;
+    /**
+     * A Uri for an icon suitable for display or null.
+     */
+    private final Uri mIconUri;
+    /**
+     * Extras for opaque use by apps/system.
+     */
+    private final Bundle mExtras;
+
+    private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
+            CharSequence description, Bitmap icon, Uri iconUri, Bundle extras) {
+        mMediaId = mediaId;
+        mTitle = title;
+        mSubtitle = subtitle;
+        mDescription = description;
+        mIcon = icon;
+        mIconUri = iconUri;
+        mExtras = extras;
+    }
+
+    private MediaDescription(Parcel in) {
+        mMediaId = in.readString();
+        mTitle = in.readCharSequence();
+        mSubtitle = in.readCharSequence();
+        mDescription = in.readCharSequence();
+        mIcon = in.readParcelable(null);
+        mIconUri = in.readParcelable(null);
+        mExtras = in.readBundle();
+    }
+
+    /**
+     * Returns the media id or null. See
+     * {@link MediaMetadata#METADATA_KEY_MEDIA_ID}.
+     */
+    public @Nullable String getMediaId() {
+        return mMediaId;
+    }
+
+    /**
+     * Returns a title suitable for display or null.
+     *
+     * @return A title or null.
+     */
+    public @Nullable CharSequence getTitle() {
+        return mTitle;
+    }
+
+    /**
+     * Returns a subtitle suitable for display or null.
+     *
+     * @return A subtitle or null.
+     */
+    public @Nullable CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+
+    /**
+     * Returns a description suitable for display or null.
+     *
+     * @return A description or null.
+     */
+    public @Nullable CharSequence getDescription() {
+        return mDescription;
+    }
+
+    /**
+     * Returns a bitmap icon suitable for display or null.
+     *
+     * @return An icon or null.
+     */
+    public @Nullable Bitmap getIconBitmap() {
+        return mIcon;
+    }
+
+    /**
+     * Returns a Uri for an icon suitable for display or null.
+     *
+     * @return An icon uri or null.
+     */
+    public @Nullable Uri getIconUri() {
+        return mIconUri;
+    }
+
+    /**
+     * Returns any extras that were added to the description.
+     *
+     * @return A bundle of extras or null.
+     */
+    public @Nullable Bundle getExtras() {
+        return mExtras;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mMediaId);
+        dest.writeCharSequence(mTitle);
+        dest.writeCharSequence(mSubtitle);
+        dest.writeCharSequence(mDescription);
+        dest.writeParcelable(mIcon, flags);
+        dest.writeParcelable(mIconUri, flags);
+        dest.writeBundle(mExtras);
+    }
+
+    @Override
+    public String toString() {
+        return mTitle + ", " + mSubtitle + ", " + mDescription;
+    }
+
+    public static final Parcelable.Creator<MediaDescription> CREATOR =
+            new Parcelable.Creator<MediaDescription>() {
+                @Override
+                public MediaDescription createFromParcel(Parcel in) {
+                    return new MediaDescription(in);
+                }
+
+                @Override
+                public MediaDescription[] newArray(int size) {
+                    return new MediaDescription[size];
+                }
+            };
+
+    /**
+     * Builder for {@link MediaDescription} objects.
+     */
+    public static class Builder {
+        private String mMediaId;
+        private CharSequence mTitle;
+        private CharSequence mSubtitle;
+        private CharSequence mDescription;
+        private Bitmap mIcon;
+        private Uri mIconUri;
+        private Bundle mExtras;
+
+        /**
+         * Creates an initially empty builder.
+         */
+        public Builder() {
+        }
+
+        /**
+         * Sets the media id.
+         *
+         * @param mediaId The unique id for the item or null.
+         * @return this
+         */
+        public Builder setMediaId(@Nullable String mediaId) {
+            mMediaId = mediaId;
+            return this;
+        }
+
+        /**
+         * Sets the title.
+         *
+         * @param title A title suitable for display to the user or null.
+         * @return this
+         */
+        public Builder setTitle(@Nullable CharSequence title) {
+            mTitle = title;
+            return this;
+        }
+
+        /**
+         * Sets the subtitle.
+         *
+         * @param subtitle A subtitle suitable for display to the user or null.
+         * @return this
+         */
+        public Builder setSubtitle(@Nullable CharSequence subtitle) {
+            mSubtitle = subtitle;
+            return this;
+        }
+
+        /**
+         * Sets the description.
+         *
+         * @param description A description suitable for display to the user or
+         *            null.
+         * @return this
+         */
+        public Builder setDescription(@Nullable CharSequence description) {
+            mDescription = description;
+            return this;
+        }
+
+        /**
+         * Sets the icon.
+         *
+         * @param icon A {@link Bitmap} icon suitable for display to the user or
+         *            null.
+         * @return this
+         */
+        public Builder setIconBitmap(@Nullable Bitmap icon) {
+            mIcon = icon;
+            return this;
+        }
+
+        /**
+         * Sets the icon uri.
+         *
+         * @param iconUri A {@link Uri} for an icon suitable for display to the
+         *            user or null.
+         * @return this
+         */
+        public Builder setIconUri(@Nullable Uri iconUri) {
+            mIconUri = iconUri;
+            return this;
+        }
+
+        /**
+         * Sets a bundle of extras.
+         *
+         * @param extras The extras to include with this description or null.
+         * @return this
+         */
+        public Builder setExtras(@Nullable Bundle extras) {
+            mExtras = extras;
+            return this;
+        }
+
+        public MediaDescription build() {
+            return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
+                    mExtras);
+        }
+    }
+}
index 74f7a96..b4e6033 100644 (file)
@@ -17,15 +17,22 @@ package android.media;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.browse.MediaBrowser;
+import android.media.session.MediaController;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
-import android.text.format.Time;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Size;
 import android.util.SparseArray;
 
 import java.util.Set;
@@ -119,7 +126,9 @@ public final class MediaMetadata implements Parcelable {
     public static final String METADATA_KEY_ART = "android.media.metadata.ART";
 
     /**
-     * The artwork for the media as a Uri.
+     * The artwork for the media as a Uri formatted String. The artwork can be
+     * loaded using a combination of {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
      */
     public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
 
@@ -130,7 +139,10 @@ public final class MediaMetadata implements Parcelable {
     public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART";
 
     /**
-     * The artwork for the album of the media's original source as a Uri.
+     * The artwork for the album of the media's original source as a Uri
+     * formatted String. The artwork can be loaded using a combination of
+     * {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
      */
     public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
 
@@ -181,13 +193,26 @@ public final class MediaMetadata implements Parcelable {
             = "android.media.metadata.DISPLAY_ICON";
 
     /**
-     * An icon or thumbnail that is suitable for display to the user. When
-     * displaying more information for media described by this metadata the
-     * display description should be preferred to other fields when present.
+     * A Uri formatted String for an icon or thumbnail that is suitable for
+     * display to the user. When displaying more information for media described
+     * by this metadata the display description should be preferred to other
+     * fields when present. The icon can be loaded using a combination of
+     * {@link ContentResolver#openInputStream} and
+     * {@link BitmapFactory#decodeStream}.
      */
     public static final String METADATA_KEY_DISPLAY_ICON_URI
             = "android.media.metadata.DISPLAY_ICON_URI";
 
+    /**
+     * A String key for identifying the content. This value is specific to the
+     * service providing the content. If used, this should be a persistent
+     * unique key for the underlying content. It may be used with
+     * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
+     * to initiate playback when provided by a {@link MediaBrowser} connected to
+     * the same app.
+     */
+    public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
+
     private static final String[] PREFERRED_DESCRIPTION_ORDER = {
             METADATA_KEY_TITLE,
             METADATA_KEY_ARTIST,
@@ -277,7 +302,7 @@ public final class MediaMetadata implements Parcelable {
     }
 
     private final Bundle mBundle;
-    private Description mDescription;
+    private MediaDescription mDescription;
 
     private MediaMetadata(Bundle bundle) {
         mBundle = new Bundle(bundle);
@@ -406,11 +431,13 @@ public final class MediaMetadata implements Parcelable {
      *
      * @return A simple description of this metadata.
      */
-    public @NonNull Description getDescription() {
+    public @NonNull MediaDescription getDescription() {
         if (mDescription != null) {
             return mDescription;
         }
 
+        String mediaId = getString(METADATA_KEY_MEDIA_ID);
+
         CharSequence[] text = new CharSequence[3];
         Bitmap icon = null;
         Uri iconUri = null;
@@ -454,7 +481,15 @@ public final class MediaMetadata implements Parcelable {
             }
         }
 
-        mDescription = new Description(text[0], text[1], text[2], icon, iconUri);
+        MediaDescription.Builder bob = new MediaDescription.Builder();
+        bob.setMediaId(mediaId);
+        bob.setTitle(text[0]);
+        bob.setSubtitle(text[1]);
+        bob.setDescription(text[2]);
+        bob.setIconBitmap(icon);
+        bob.setIconUri(iconUri);
+        mDescription = bob.build();
+
         return mDescription;
     }
 
@@ -668,90 +703,4 @@ public final class MediaMetadata implements Parcelable {
             return new MediaMetadata(mBundle);
         }
     }
-
-    /**
-     * A simple form of the metadata that can be used for display.
-     */
-    public final class Description {
-        /**
-         * A primary title suitable for display or null.
-         */
-        private final CharSequence mTitle;
-        /**
-         * A subtitle suitable for display or null.
-         */
-        private final CharSequence mSubtitle;
-        /**
-         * A description suitable for display or null.
-         */
-        private final CharSequence mDescription;
-        /**
-         * A bitmap icon suitable for display or null.
-         */
-        private final Bitmap mIcon;
-        /**
-         * A Uri for an icon suitable for display or null.
-         */
-        private final Uri mIconUri;
-
-        /**
-         * Returns the best available title or null.
-         *
-         * @return A title or null.
-         */
-        public @Nullable CharSequence getTitle() {
-            return mTitle;
-        }
-
-        /**
-         * Returns the best available subtitle or null.
-         *
-         * @return A subtitle or null.
-         */
-        public @Nullable CharSequence getSubtitle() {
-            return mSubtitle;
-        }
-
-        /**
-         * Returns the best available description or null.
-         *
-         * @return A description or null.
-         */
-        public @Nullable CharSequence getDescription() {
-            return mDescription;
-        }
-
-        /**
-         * Returns the best available icon or null.
-         *
-         * @return An icon or null.
-         */
-        public @Nullable Bitmap getIcon() {
-            return mIcon;
-        }
-
-        /**
-         * Returns the best available icon Uri or null.
-         *
-         * @return An icon uri or null.
-         */
-        public @Nullable Uri getIconUri() {
-            return mIconUri;
-        }
-
-        private Description(CharSequence title, CharSequence subtitle, CharSequence description,
-                Bitmap icon, Uri iconUri) {
-            mTitle = title;
-            mSubtitle = subtitle;
-            mDescription = description;
-            mIcon = icon;
-            mIconUri = iconUri;
-        }
-
-        @Override
-        public String toString() {
-            return mTitle + ", " + mSubtitle + ", " + mDescription;
-        }
-    }
-
 }
index 1c6d81f..debaf45 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.media.browse;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.ComponentName;
@@ -23,26 +24,27 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.content.pm.ParceledListSlice;
-import android.content.res.Configuration;
-import android.graphics.Bitmap;
+import android.media.MediaDescription;
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.os.RemoteException;
+import android.service.media.MediaBrowserService;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
-import android.util.SparseArray;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
-import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
-import java.util.Objects;
-import java.util.Set;
 
 /**
  * Browses media content offered by a link MediaBrowserService.
@@ -67,8 +69,6 @@ public final class MediaBrowser {
     private final Handler mHandler = new Handler();
     private final ArrayMap<Uri,Subscription> mSubscriptions =
             new ArrayMap<Uri, MediaBrowser.Subscription>();
-    private final SparseArray<IconRequest> mIconRequests =
-            new SparseArray<IconRequest>();
 
     private int mState = CONNECT_STATE_DISCONNECTED;
     private MediaServiceConnection mServiceConnection;
@@ -77,7 +77,6 @@ public final class MediaBrowser {
     private Uri mRootUri;
     private MediaSession.Token mMediaSessionToken;
     private Bundle mExtras;
-    private int mNextSeq;
 
     /**
      * Creates a media browser for the specified media browse service.
@@ -363,49 +362,6 @@ public final class MediaBrowser {
     }
 
     /**
-     * Loads the icon of a media item.
-     *
-     * @param uri The uri of the Icon.
-     * @param width The preferred width of the icon in dp.
-     * @param height The preferred width of the icon in dp.
-     * @param callback The callback to receive the icon.
-     */
-    public void loadIcon(final @NonNull Uri uri, final int width, final int height,
-            final @NonNull IconCallback callback) {
-        if (uri == null) {
-            throw new IllegalArgumentException("Icon uri cannot be null");
-        }
-        if (callback == null) {
-            throw new IllegalArgumentException("Icon callback cannot be null");
-        }
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                for (int i = 0; i < mIconRequests.size(); i++) {
-                    IconRequest existingRequest = mIconRequests.valueAt(i);
-                    if (existingRequest.isSameRequest(uri, width, height)) {
-                        existingRequest.addCallback(callback);
-                        return;
-                    }
-                }
-                final int seq = mNextSeq++;
-                IconRequest request = new IconRequest(seq, uri, width, height);
-                request.addCallback(callback);
-                mIconRequests.put(seq, request);
-                if (mState == CONNECT_STATE_CONNECTED) {
-                    try {
-                        mServiceBinder.loadIcon(seq, uri, width, height, mServiceCallbacks);
-                    } catch (RemoteException e) {
-                        // Process is crashing.  We will disconnect, and upon reconnect we will
-                        // automatically reload the icons. So nothing to do here.
-                        Log.d(TAG, "loadIcon failed with RemoteException uri=" + uri);
-                    }
-                }
-            }
-        });
-    }
-
-    /**
      * For debugging.
      */
     private static String getStateLabel(int state) {
@@ -461,18 +417,6 @@ public final class MediaBrowser {
                         Log.d(TAG, "addSubscription failed with RemoteException parentUri=" + uri);
                     }
                 }
-
-                for (int i = 0; i < mIconRequests.size(); i++) {
-                    IconRequest request = mIconRequests.valueAt(i);
-                    try {
-                        mServiceBinder.loadIcon(request.mSeq, request.mUri,
-                                request.mWidth, request.mHeight, mServiceCallbacks);
-                    } catch (RemoteException e) {
-                        // Process is crashing.  We will disconnect, and upon reconnect we will
-                        // automatically reload. So nothing to do here.
-                        Log.d(TAG, "loadIcon failed with RemoteException request=" + request);
-                    }
-                }
             }
         });
     }
@@ -515,7 +459,7 @@ public final class MediaBrowser {
                     return;
                 }
 
-                List<MediaBrowserItem> data = list.getList();
+                List<MediaItem> data = list.getList();
                 if (DBG) {
                     Log.d(TAG, "onLoadChildren for " + mServiceComponent + " uri=" + uri);
                 }
@@ -539,32 +483,6 @@ public final class MediaBrowser {
         });
     }
 
-    private final void onLoadIcon(final IMediaBrowserServiceCallbacks callback,
-            final int seqNum, final Bitmap bitmap) {
-        mHandler.post(new Runnable() {
-            @Override
-            public void run() {
-                // Check that there hasn't been a disconnect or a different
-                // ServiceConnection.
-                if (!isCurrent(callback, "onLoadIcon")) {
-                    return;
-                }
-
-                IconRequest request = mIconRequests.get(seqNum);
-                if (request == null) {
-                    Log.d(TAG, "onLoadIcon called for seqNum=" + seqNum + " request="
-                            + request + " but the request is not registered");
-                    return;
-                }
-                mIconRequests.delete(seqNum);
-                for (IconCallback IconCallback : request.getCallbacks()) {
-                    IconCallback.onIconLoaded(request.mUri, bitmap);
-                }
-            }
-        });
-    }
-
-
     /**
      * Return true if {@code callback} is the current ServiceCallbacks.  Also logs if it's not.
      */
@@ -600,130 +518,169 @@ public final class MediaBrowser {
         Log.d(TAG, "  mMediaSessionToken=" + mMediaSessionToken);
     }
 
+    public static class MediaItem implements Parcelable {
+        private final int mFlags;
+        private final MediaDescription mDescription;
+
+        /** @hide */
+        @Retention(RetentionPolicy.SOURCE)
+        @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
+        public @interface Flags { }
 
-    /**
-     * Callbacks for connection related events.
-     */
-    public static class ConnectionCallback {
         /**
-         * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
+         * Flag: Indicates that the item has children of its own.
          */
-        public void onConnected() {
+        public static final int FLAG_BROWSABLE = 1 << 0;
+
+        /**
+         * Flag: Indicates that the item is playable.
+         * <p>
+         * The Uri of this item may be passed to link android.media.session.MediaController#play(Uri)
+         * to start playing it.
+         * </p>
+         */
+        public static final int FLAG_PLAYABLE = 1 << 1;
+
+        /**
+         * Create a new MediaItem for use in browsing media.
+         *
+         * @param flags The flags for this item.
+         * @param description The description of the media, which must include a
+         *            media id.
+         */
+        public MediaItem(@Flags int flags, @NonNull MediaDescription description) {
+            if (description == null) {
+                throw new IllegalArgumentException("description cannot be null");
+            }
+            if (TextUtils.isEmpty(description.getMediaId())) {
+                throw new IllegalArgumentException("description must have a non-empty media id");
+            }
+            mFlags = flags;
+            mDescription = description;
         }
 
         /**
-         * Invoked when the client is disconnected from the media browser.
+         * Private constructor.
          */
-        public void onConnectionSuspended() {
+        private MediaItem(Parcel in) {
+            mFlags = in.readInt();
+            mDescription = MediaDescription.CREATOR.createFromParcel(in);
         }
 
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            out.writeInt(mFlags);
+            mDescription.writeToParcel(out, flags);
+        }
+
+        @Override
+        public String toString() {
+            final StringBuilder sb = new StringBuilder("MediaItem{");
+            sb.append("mFlags=").append(mFlags);
+            sb.append(", mDescription=").append(mDescription);
+            sb.append('}');
+            return sb.toString();
+        }
+
+        public static final Parcelable.Creator<MediaItem> CREATOR =
+                new Parcelable.Creator<MediaItem>() {
+                    @Override
+                    public MediaItem createFromParcel(Parcel in) {
+                        return new MediaItem(in);
+                    }
+
+                    @Override
+                    public MediaItem[] newArray(int size) {
+                        return new MediaItem[size];
+                    }
+                };
+
         /**
-         * Invoked when the connection to the media browser failed.
+         * Gets the flags of the item.
          */
-        public void onConnectionFailed() {
+        public @Flags int getFlags() {
+            return mFlags;
         }
-    }
 
-    /**
-     * Callbacks for subscription related events.
-     */
-    public static abstract class SubscriptionCallback {
         /**
-         * Called when the list of children is loaded or updated.
+         * Returns whether this item is browsable.
+         * @see #FLAG_BROWSABLE
          */
-        public void onChildrenLoaded(@NonNull Uri parentUri,
-                                     @NonNull List<MediaBrowserItem> children) {
+        public boolean isBrowsable() {
+            return (mFlags & FLAG_BROWSABLE) != 0;
         }
 
         /**
-         * Called when the Uri doesn't exist or other errors in subscribing.
-         * <p>
-         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
-         * called, because some errors may heal themselves.
-         * </p>
+         * Returns whether this item is playable.
+         * @see #FLAG_PLAYABLE
          */
-        public void onError(@NonNull Uri uri) {
+        public boolean isPlayable() {
+            return (mFlags & FLAG_PLAYABLE) != 0;
         }
-    }
 
-    /**
-     * Callbacks for icon loading.
-     */
-    public static abstract class IconCallback {
         /**
-         * Called when the icon is loaded.
+         * Returns the description of the media.
          */
-        public void onIconLoaded(@NonNull Uri uri, @NonNull Bitmap bitmap) {
+        public @NonNull MediaDescription getDescription() {
+            return mDescription;
         }
 
         /**
-         * Called when the Uri doesn’t exist or the bitmap cannot be loaded.
+         * Returns the media id for this item.
          */
-        public void onError(@NonNull Uri uri) {
+        public @NonNull String getMediaId() {
+            return mDescription.getMediaId();
         }
     }
 
-    private static class IconRequest {
-        final int mSeq;
-        final Uri mUri;
-        final int mWidth;
-        final int mHeight;
-        final List<IconCallback> mCallbacks;
 
+    /**
+     * Callbacks for connection related events.
+     */
+    public static class ConnectionCallback {
         /**
-         * Constructs an icon request.
-         * @param seq The unique sequence number assigned to the request by the media browser.
-         * @param uri The Uri for the icon.
-         * @param width The width for the icon.
-         * @param height The height for the icon.
+         * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
          */
-        IconRequest(int seq, @NonNull Uri uri, int width, int height) {
-            if (uri == null) {
-                throw new IllegalArgumentException("Icon uri cannot be null");
-            }
-            this.mSeq = seq;
-            this.mUri = uri;
-            this.mWidth = width;
-            this.mHeight = height;
-            mCallbacks = new ArrayList<IconCallback>();
+        public void onConnected() {
         }
 
         /**
-         * Adds a callback to the icon request.
-         * If the callback already exists, it will not be added again.
+         * Invoked when the client is disconnected from the media browser.
          */
-        public void addCallback(@NonNull IconCallback callback) {
-            if (callback == null) {
-                throw new IllegalArgumentException("callback cannot be null in IconRequest");
-            }
-            if (!mCallbacks.contains(callback)) {
-                mCallbacks.add(callback);
-            }
+        public void onConnectionSuspended() {
         }
 
         /**
-         * Checks if the icon request has the same uri, width, and height as the given values.
+         * Invoked when the connection to the media browser failed.
          */
-        public boolean isSameRequest(@Nullable Uri uri, int width, int height) {
-            return Objects.equals(mUri, uri) && mWidth == width && mHeight == height;
+        public void onConnectionFailed() {
         }
+    }
 
-        @Override
-        public String toString() {
-            final StringBuilder sb = new StringBuilder("IconRequest{");
-            sb.append("uri=").append(mUri);
-            sb.append(", width=").append(mWidth);
-            sb.append(", height=").append(mHeight);
-            sb.append(", seq=").append(mSeq);
-            sb.append('}');
-            return sb.toString();
+    /**
+     * Callbacks for subscription related events.
+     */
+    public static abstract class SubscriptionCallback {
+        /**
+         * Called when the list of children is loaded or updated.
+         */
+        public void onChildrenLoaded(@NonNull Uri parentUri,
+                                     @NonNull List<MediaItem> children) {
         }
 
         /**
-         * Gets an unmodifiable view of the list of callbacks associated with the request.
+         * Called when the Uri doesn't exist or other errors in subscribing.
+         * <p>
+         * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
+         * called, because some errors may heal themselves.
+         * </p>
          */
-        public List<IconCallback> getCallbacks() {
-            return Collections.unmodifiableList(mCallbacks);
+        public void onError(@NonNull Uri uri) {
         }
     }
 
@@ -809,7 +766,7 @@ public final class MediaBrowser {
             }
             return true;
         }
-    };
+    }
 
     /**
      * Callbacks from the service.
@@ -852,14 +809,6 @@ public final class MediaBrowser {
                 mediaBrowser.onLoadChildren(this, uri, list);
             }
         }
-
-        @Override
-        public void onLoadIcon(final int seqNum, final Bitmap bitmap) {
-            MediaBrowser mediaBrowser = mMediaBrowser.get();
-            if (mediaBrowser != null) {
-                mediaBrowser.onLoadIcon(this, seqNum, bitmap);
-            }
-        }
     }
 
     private static class Subscription {
diff --git a/media/java/android/media/browse/MediaBrowserItem.java b/media/java/android/media/browse/MediaBrowserItem.java
deleted file mode 100644 (file)
index 47ec46b..0000000
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Copyright (C) 2014 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 android.media.browse;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.net.Uri;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Describes a media item in the list of items offered by a {@link MediaBrowserService}.
- */
-public final class MediaBrowserItem implements Parcelable {
-    private final Uri mUri;
-    private final int mFlags;
-    private final CharSequence mTitle;
-    private final CharSequence mSummary;
-    private final Uri mIconUri;
-    private final int mIconResourceId;
-    private final Bundle mExtras;
-
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef(flag=true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
-    public @interface Flags { }
-
-    /**
-     * Flag: Indicates that the item has children of its own.
-     */
-    public static final int FLAG_BROWSABLE = 1 << 0;
-
-    /**
-     * Flag: Indicates that the item is playable.
-     * <p>
-     * The Uri of this item may be passed to link android.media.session.MediaController#play(Uri)
-     * to start playing it.
-     * </p>
-     */
-    public static final int FLAG_PLAYABLE = 1 << 1;
-
-    /**
-     * Initialize a MediaBrowserItem object.
-     */
-    private MediaBrowserItem(@NonNull Uri uri, int flags, @NonNull CharSequence title,
-            CharSequence summary, @Nullable Uri iconUri, int iconResourceId, Bundle extras) {
-        if (uri == null) {
-            throw new IllegalArgumentException("uri can not be null");
-        }
-        if (title == null) {
-            throw new IllegalArgumentException("title can not be null");
-        }
-        mUri = uri;
-        mFlags = flags;
-        mTitle = title;
-        mSummary = summary;
-        mIconUri = iconUri;
-        mIconResourceId = iconResourceId;
-        mExtras = extras;
-    }
-
-    /**
-     * Private constructor.
-     */
-    private MediaBrowserItem(Parcel in) {
-        mUri = Uri.CREATOR.createFromParcel(in);
-        mFlags = in.readInt();
-        mTitle = in.readCharSequence();
-        if (in.readInt() != 0) {
-            mSummary = in.readCharSequence();
-        } else {
-            mSummary = null;
-        }
-        if (in.readInt() != 0) {
-            mIconUri = Uri.CREATOR.createFromParcel(in);
-        } else {
-            mIconUri = null;
-        }
-        mIconResourceId = in.readInt();
-        if (in.readInt() != 0) {
-            mExtras = Bundle.CREATOR.createFromParcel(in);
-        } else {
-            mExtras = null;
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        mUri.writeToParcel(out, flags);
-        out.writeInt(mFlags);
-        out.writeCharSequence(mTitle);
-        if (mSummary != null) {
-            out.writeInt(1);
-            out.writeCharSequence(mSummary);
-        } else {
-            out.writeInt(0);
-        }
-        if (mIconUri != null) {
-            out.writeInt(1);
-            mIconUri.writeToParcel(out, flags);
-        } else {
-            out.writeInt(0);
-        }
-        out.writeInt(mIconResourceId);
-        if (mExtras != null) {
-            out.writeInt(1);
-            mExtras.writeToParcel(out, flags);
-        } else {
-            out.writeInt(0);
-        }
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder("MediaBrowserItem{");
-        sb.append("mUri=").append(mUri);
-        sb.append(", mFlags=").append(mFlags);
-        sb.append(", mTitle=").append(mTitle);
-        sb.append(", mSummary=").append(mSummary);
-        sb.append(", mIconUri=").append(mIconUri);
-        sb.append(", mIconResourceId=").append(mIconResourceId);
-        sb.append('}');
-        return sb.toString();
-    }
-
-    public static final Parcelable.Creator<MediaBrowserItem> CREATOR =
-            new Parcelable.Creator<MediaBrowserItem>() {
-                @Override
-                public MediaBrowserItem createFromParcel(Parcel in) {
-                    return new MediaBrowserItem(in);
-                }
-
-                @Override
-                public MediaBrowserItem[] newArray(int size) {
-                    return new MediaBrowserItem[size];
-                }
-            };
-
-    /**
-     * Gets the Uri of the item.
-     */
-    public @NonNull Uri getUri() {
-        return mUri;
-    }
-
-    /**
-     * Gets the flags of the item.
-     */
-    public @Flags int getFlags() {
-        return mFlags;
-    }
-
-    /**
-     * Returns whether this item is browsable.
-     * @see #FLAG_BROWSABLE
-     */
-    public boolean isBrowsable() {
-        return (mFlags & FLAG_BROWSABLE) != 0;
-    }
-
-    /**
-     * Returns whether this item is playable.
-     * @see #FLAG_PLAYABLE
-     */
-    public boolean isPlayable() {
-        return (mFlags & FLAG_PLAYABLE) != 0;
-    }
-
-    /**
-     * Gets the title of the item.
-     * @more
-     * The title will be shown as the first line of text when
-     * describing each item to the user.
-     */
-    public @NonNull CharSequence getTitle() {
-        return mTitle;
-    }
-
-    /**
-     * Gets summary of the item, or null if none.
-     * @more
-     * The summary will be shown as the second line of text when
-     * describing each item to the user.
-     */
-    public @Nullable CharSequence getSummary() {
-        return mSummary;
-    }
-
-    /**
-     * Gets the Uri of the icon.
-     */
-    public @Nullable Uri getIconUri() {
-        return mIconUri;
-    }
-
-    /**
-     * Gets the resource id of the icon.
-     */
-    public @DrawableRes int getIconResourceId() {
-        return mIconResourceId;
-    }
-
-    /**
-     * Gets additional service-specified extras about the
-     * item or its content, or null if none.
-     */
-    public @Nullable Bundle getExtras() {
-        return mExtras;
-    }
-
-    /**
-     * Builder for {@link MediaBrowserItem} objects.
-     */
-    public static final class Builder {
-        private final Uri mUri;
-        private final int mFlags;
-        private final CharSequence mTitle;
-        private CharSequence mSummary;
-        private Uri mIconUri;
-        private int mIconResourceId;
-        private Bundle mExtras;
-
-        /**
-         * Creates an item builder.
-         */
-        public Builder(@NonNull Uri uri, @Flags int flags, @NonNull CharSequence title) {
-            if (uri == null) {
-                throw new IllegalArgumentException("uri can not be null");
-            }
-            if (title == null) {
-                throw new IllegalArgumentException("title can not be null");
-            }
-            mUri = uri;
-            mFlags = flags;
-            mTitle = title;
-        }
-
-        /**
-         * Sets summary of the item, or null if none.
-         */
-        public @NonNull Builder setSummary(@Nullable CharSequence summary) {
-            mSummary = summary;
-            return this;
-        }
-
-        /**
-         * Sets the uri of the icon.
-         * <p>
-         * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be called.
-         * If both are specified, the resource id will be used to load the icon.
-         * </p>
-         */
-        public @NonNull Builder setIconUri(@Nullable Uri iconUri) {
-            mIconUri = iconUri;
-            return this;
-        }
-
-        /**
-         * Sets the resource id of the icon.
-         * <p>
-         * Either {@link #setIconUri(Uri)} or {@link #setIconResourceId(int)} should be specified.
-         * If both are specified, the resource id will be used to load the icon.
-         * </p>
-         */
-        public @NonNull Builder setIconResourceId(@DrawableRes int ResourceId) {
-            mIconResourceId = ResourceId;
-            return this;
-        }
-
-        /**
-         * Sets additional service-specified extras about the
-         * item or its content.
-         */
-        public @NonNull Builder setExtras(@Nullable Bundle extras) {
-            mExtras = extras;
-            return this;
-        }
-
-        /**
-         * Builds the item.
-         */
-        public @NonNull MediaBrowserItem build() {
-            return new MediaBrowserItem(mUri, mFlags, mTitle, mSummary, mIconUri,
-                    mIconResourceId, mExtras);
-        }
-    }
-}
-
index 9911129..49087b0 100644 (file)
@@ -30,7 +30,7 @@ oneway interface ISessionCallback {
 
     // These callbacks are for the TransportPerformer
     void onPlay();
-    void onPlayUri(in Uri uri, in Bundle extras);
+    void onPlayFromMediaId(String uri, in Bundle extras);
     void onPlayFromSearch(String query, in Bundle extras);
     void onSkipToTrack(long id);
     void onPause();
index 6b80477..d684688 100644 (file)
@@ -51,9 +51,9 @@ interface ISessionController {
 
     // These commands are for the TransportControls
     void play();
-    void playUri(in Uri uri, in Bundle extras);
+    void playFromMediaId(String uri, in Bundle extras);
     void playFromSearch(String string, in Bundle extras);
-    void skipToTrack(long id);
+    void skipToQueueItem(long id);
     void pause();
     void stop();
     void next();
index d7baaa9..9641f83 100644 (file)
@@ -173,7 +173,7 @@ public final class MediaController {
      *
      * @return The current play queue or null.
      */
-    public @Nullable List<MediaSession.Item> getQueue() {
+    public @Nullable List<MediaSession.QueueItem> getQueue() {
         try {
             ParceledListSlice queue = mSessionBinder.getQueue();
             if (queue != null) {
@@ -538,9 +538,9 @@ public final class MediaController {
          * @param queue A list of items in the current play queue. It should
          *            include the currently playing item as well as previous and
          *            upcoming items if applicable.
-         * @see MediaSession.Item
+         * @see MediaSession.QueueItem
          */
-        public void onQueueChanged(@Nullable List<MediaSession.Item> queue) {
+        public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
         }
 
         /**
@@ -594,18 +594,19 @@ public final class MediaController {
         /**
          * Request that the player start playback for a specific {@link Uri}.
          *
-         * @param uri The uri of the requested media.
+         * @param mediaId The uri of the requested media.
          * @param extras Optional extras that can include extra information about the media item
          *               to be played.
          */
-        public void playUri(Uri uri, Bundle extras) {
-            if (uri == null) {
-                throw new IllegalArgumentException("You must specify a non-null Uri for playUri.");
+        public void playFromMediaId(String mediaId, Bundle extras) {
+            if (TextUtils.isEmpty(mediaId)) {
+                throw new IllegalArgumentException(
+                        "You must specify a non-empty String for playFromMediaId.");
             }
             try {
-                mSessionBinder.playUri(uri, extras);
+                mSessionBinder.playFromMediaId(mediaId, extras);
             } catch (RemoteException e) {
-                Log.wtf(TAG, "Error calling play(" + uri + ").", e);
+                Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
             }
         }
 
@@ -631,9 +632,9 @@ public final class MediaController {
          * Play an item with a specific id in the play queue. If you specify an
          * id that is not in the play queue, the behavior is undefined.
          */
-        public void skipToItem(long id) {
+        public void skipToQueueItem(long id) {
             try {
-                mSessionBinder.skipToTrack(id);
+                mSessionBinder.skipToQueueItem(id);
             } catch (RemoteException e) {
                 Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
             }
@@ -904,7 +905,7 @@ public final class MediaController {
 
         @Override
         public void onQueueChanged(ParceledListSlice parceledQueue) {
-            List<MediaSession.Item> queue = parceledQueue.getList();
+            List<MediaSession.QueueItem> queue = parceledQueue.getList();
             MediaController controller = mController.get();
             if (controller != null) {
                 controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
@@ -960,7 +961,7 @@ public final class MediaController {
                     mCallback.onMetadataChanged((MediaMetadata) msg.obj);
                     break;
                 case MSG_UPDATE_QUEUE:
-                    mCallback.onQueueChanged((List<MediaSession.Item>) msg.obj);
+                    mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
                     break;
                 case MSG_UPDATE_QUEUE_TITLE:
                     mCallback.onQueueTitleChanged((CharSequence) msg.obj);
index 0ad58c4..f657cef 100644 (file)
@@ -16,4 +16,4 @@
 package android.media.session;
 
 parcelable MediaSession.Token;
-parcelable MediaSession.Track;
\ No newline at end of file
+parcelable MediaSession.QueueItem;
\ No newline at end of file
index 1670097..f70b217 100644 (file)
@@ -25,6 +25,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioAttributes;
+import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -38,6 +39,7 @@ import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.UserHandle;
+import android.service.media.MediaBrowserService;
 import android.text.TextUtils;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -418,9 +420,9 @@ public final class MediaSession {
      *
      * @param queue A list of items in the play queue.
      */
-    public void setQueue(@Nullable List<Item> queue) {
+    public void setQueue(@Nullable List<QueueItem> queue) {
         try {
-            mBinder.setQueue(new ParceledListSlice<Item>(queue));
+            mBinder.setQueue(new ParceledListSlice<QueueItem>(queue));
         } catch (RemoteException e) {
             Log.wtf("Dead object in setQueue.", e);
         }
@@ -478,8 +480,8 @@ public final class MediaSession {
         postToCallback(CallbackMessageHandler.MSG_PLAY);
     }
 
-    private void dispatchPlayUri(Uri uri, Bundle extras) {
-        postToCallback(CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
+    private void dispatchPlayFromMediaId(String mediaId, Bundle extras) {
+        postToCallback(CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
     }
 
     private void dispatchPlayFromSearch(String query, Bundle extras) {
@@ -744,9 +746,10 @@ public final class MediaSession {
         }
 
         /**
-         * Override to handle requests to play a specific {@link Uri}.
+         * Override to handle requests to play a specific mediaId that was
+         * provided by your app's {@link MediaBrowserService}.
          */
-        public void onPlayUri(Uri uri, Bundle extras) {
+        public void onPlayFromMediaId(String mediaId, Bundle extras) {
         }
 
         /**
@@ -759,7 +762,7 @@ public final class MediaSession {
          * Override to handle requests to play an item with a given id from the
          * play queue.
          */
-        public void onSkipToItem(long id) {
+        public void onSkipToQueueItem(long id) {
         }
 
         /**
@@ -872,10 +875,10 @@ public final class MediaSession {
         }
 
         @Override
-        public void onPlayUri(Uri uri, Bundle extras) {
+        public void onPlayFromMediaId(String mediaId, Bundle extras) {
             MediaSession session = mMediaSession.get();
             if (session != null) {
-                session.dispatchPlayUri(uri, extras);
+                session.dispatchPlayFromMediaId(mediaId, extras);
             }
         }
 
@@ -990,125 +993,59 @@ public final class MediaSession {
     }
 
     /**
-     * A single item that is part of the play queue. It contains information
-     * necessary to display a single item in the queue.
+     * A single item that is part of the play queue. It contains a description
+     * of the item and its id in the queue.
      */
-    public static final class Item implements Parcelable {
+    public static final class QueueItem implements Parcelable {
         /**
          * This id is reserved. No items can be explicitly asigned this id.
          */
         public static final int UNKNOWN_ID = -1;
 
-        private final MediaMetadata mMetadata;
+        private final MediaDescription mDescription;
         private final long mId;
-        private final Uri mUri;
-        private final Bundle mExtras;
 
         /**
-         * Create a new {@link MediaSession.Item}.
+         * Create a new {@link MediaSession.QueueItem}.
          *
-         * @param metadata The metadata for this item.
+         * @param description The {@link MediaDescription} for this item.
          * @param id An identifier for this item. It must be unique within the
-         *            play queue.
-         * @param uri The uri for this item.
-         * @param extras A bundle of extras that can be used to add extra
-         *            information about this item.
+         *            play queue and cannot be {@link #UNKNOWN_ID}.
          */
-        private Item(MediaMetadata metadata, long id, Uri uri, Bundle extras) {
-            mMetadata = metadata;
+        public QueueItem(MediaDescription description, long id) {
+            if (description == null) {
+                throw new IllegalArgumentException("Description cannot be null.");
+            }
+            if (id == UNKNOWN_ID) {
+                throw new IllegalArgumentException("Id cannot be QueueItem.UNKNOWN_ID");
+            }
+            mDescription = description;
             mId = id;
-            mUri = uri;
-            mExtras = extras;
         }
 
-        private Item(Parcel in) {
-            mMetadata = MediaMetadata.CREATOR.createFromParcel(in);
+        private QueueItem(Parcel in) {
+            mDescription = MediaDescription.CREATOR.createFromParcel(in);
             mId = in.readLong();
-            mUri = Uri.CREATOR.createFromParcel(in);
-            mExtras = in.readBundle();
         }
 
         /**
-         * Get the metadata for this item.
+         * Get the description for this item.
          */
-        public MediaMetadata getMetadata() {
-            return mMetadata;
+        public MediaDescription getDescription() {
+            return mDescription;
         }
 
         /**
-         * Get the id for this item.
+         * Get the queue id for this item.
          */
-        public long getId() {
+        public long getQueueId() {
             return mId;
         }
 
-        /**
-         * Get the Uri for this item.
-         */
-        public Uri getUri() {
-            return mUri;
-        }
-
-        /**
-         * Get the extras for this item.
-         */
-        public Bundle getExtras() {
-            return mExtras;
-        }
-
-        /**
-         * Builder for {@link MediaSession.Item} objects.
-         */
-        public static final class Builder {
-            private final MediaMetadata mMetadata;
-            private final long mId;
-            private final Uri mUri;
-
-            private Bundle mExtras;
-
-            /**
-             * Create a builder with the metadata, id, and uri already set.
-             */
-            public Builder(MediaMetadata metadata, long id, Uri uri) {
-                if (metadata == null) {
-                    throw new IllegalArgumentException(
-                            "You must specify a non-null MediaMetadata to build an Item.");
-                }
-                if (uri == null) {
-                    throw new IllegalArgumentException(
-                            "You must specify a non-null Uri to build an Item.");
-                }
-                if (id == UNKNOWN_ID) {
-                    throw new IllegalArgumentException(
-                            "You must specify an id other than UNKNOWN_ID to build an Item.");
-                }
-                mMetadata = metadata;
-                mId = id;
-                mUri = uri;
-            }
-
-            /**
-             * Set optional extras for the item.
-             */
-            public MediaSession.Item.Builder setExtras(Bundle extras) {
-                mExtras = extras;
-                return this;
-            }
-
-            /**
-             * Create the {@link Item}.
-             */
-            public MediaSession.Item build() {
-                return new MediaSession.Item(mMetadata, mId, mUri, mExtras);
-            }
-        }
-
         @Override
         public void writeToParcel(Parcel dest, int flags) {
-            mMetadata.writeToParcel(dest, flags);
+            mDescription.writeToParcel(dest, flags);
             dest.writeLong(mId);
-            mUri.writeToParcel(dest, flags);
-            dest.writeBundle(mExtras);
         }
 
         @Override
@@ -1116,28 +1053,24 @@ public final class MediaSession {
             return 0;
         }
 
-        public static final Creator<MediaSession.Item> CREATOR
-                = new Creator<MediaSession.Item>() {
+        public static final Creator<MediaSession.QueueItem> CREATOR = new Creator<MediaSession.QueueItem>() {
 
             @Override
-            public MediaSession.Item createFromParcel(Parcel p) {
-                return new MediaSession.Item(p);
+            public MediaSession.QueueItem createFromParcel(Parcel p) {
+                return new MediaSession.QueueItem(p);
             }
 
             @Override
-            public MediaSession.Item[] newArray(int size) {
-                return new MediaSession.Item[size];
+            public MediaSession.QueueItem[] newArray(int size) {
+                return new MediaSession.QueueItem[size];
             }
         };
 
         @Override
         public String toString() {
-            return "MediaSession.Item {" +
-                    "Metadata=" + mMetadata +
-                    ", Id=" + mId +
-                    ", Uri=" + mUri +
-                    ", Extras=" + mExtras +
-                    " }";
+            return "MediaSession.QueueItem {" +
+                    "Description=" + mDescription +
+                    ", Id=" + mId + " }";
         }
     }
 
@@ -1156,7 +1089,7 @@ public final class MediaSession {
     private class CallbackMessageHandler extends Handler {
 
         private static final int MSG_PLAY = 1;
-        private static final int MSG_PLAY_URI = 2;
+        private static final int MSG_PLAY_MEDIA_ID = 2;
         private static final int MSG_PLAY_SEARCH = 3;
         private static final int MSG_SKIP_TO_ITEM = 4;
         private static final int MSG_PAUSE = 5;
@@ -1202,14 +1135,14 @@ public final class MediaSession {
                 case MSG_PLAY:
                     mCallback.onPlay();
                     break;
-                case MSG_PLAY_URI:
-                    mCallback.onPlayUri((Uri) msg.obj, msg.getData());
+                case MSG_PLAY_MEDIA_ID:
+                    mCallback.onPlayFromMediaId((String) msg.obj, msg.getData());
                     break;
                 case MSG_PLAY_SEARCH:
                     mCallback.onPlayFromSearch((String) msg.obj, msg.getData());
                     break;
                 case MSG_SKIP_TO_ITEM:
-                    mCallback.onSkipToItem((Long) msg.obj);
+                    mCallback.onSkipToQueueItem((Long) msg.obj);
                 case MSG_PAUSE:
                     mCallback.onPause();
                     break;
index 2ca97dd..267d1ff 100644 (file)
@@ -36,95 +36,95 @@ public final class PlaybackState implements Parcelable {
     private static final String TAG = "PlaybackState";
 
     /**
-     * Indicates this performer supports the stop command.
+     * Indicates this session supports the stop command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_STOP = 1 << 0;
 
     /**
-     * Indicates this performer supports the pause command.
+     * Indicates this session supports the pause command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_PAUSE = 1 << 1;
 
     /**
-     * Indicates this performer supports the play command.
+     * Indicates this session supports the play command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_PLAY = 1 << 2;
 
     /**
-     * Indicates this performer supports the rewind command.
+     * Indicates this session supports the rewind command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_REWIND = 1 << 3;
 
     /**
-     * Indicates this performer supports the previous command.
+     * Indicates this session supports the previous command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
 
     /**
-     * Indicates this performer supports the next command.
+     * Indicates this session supports the next command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
 
     /**
-     * Indicates this performer supports the fast forward command.
+     * Indicates this session supports the fast forward command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_FAST_FORWARD = 1 << 6;
 
     /**
-     * Indicates this performer supports the set rating command.
+     * Indicates this session supports the set rating command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_SET_RATING = 1 << 7;
 
     /**
-     * Indicates this performer supports the seek to command.
+     * Indicates this session supports the seek to command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_SEEK_TO = 1 << 8;
 
     /**
-     * Indicates this performer supports the play/pause toggle command.
+     * Indicates this session supports the play/pause toggle command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_PLAY_PAUSE = 1 << 9;
 
     /**
-     * Indicates this performer supports the play from uri command.
+     * Indicates this session supports the play from media id command.
      *
      * @see Builder#setActions(long)
      */
-    public static final long ACTION_PLAY_URI = 1 << 10;
+    public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
 
     /**
-     * Indicates this performer supports the play from search command.
+     * Indicates this session supports the play from search command.
      *
      * @see Builder#setActions(long)
      */
     public static final long ACTION_PLAY_FROM_SEARCH = 1 << 11;
 
     /**
-     * Indicates this performer supports the skip to item command.
+     * Indicates this session supports the skip to queue item command.
      *
      * @see Builder#setActions(long)
      */
-    public static final long ACTION_SKIP_TO_ITEM = 1 << 12;
+    public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
 
     /**
      * This is the default playback state and indicates that no media has been
@@ -211,6 +211,14 @@ public final class PlaybackState implements Parcelable {
     public final static int STATE_SKIPPING_TO_NEXT = 10;
 
     /**
+     * State indicating the player is currently skipping to a specific item in
+     * the queue.
+     *
+     * @see Builder#setState
+     */
+    public final static int STATE_SKIPPING_TO_QUEUE_ITEM = 11;
+
+    /**
      * Use this value for the position to indicate the position is not known.
      */
     public final static long PLAYBACK_POSITION_UNKNOWN = -1;
@@ -374,6 +382,18 @@ public final class PlaybackState implements Parcelable {
     }
 
     /**
+     * Get the id of the currently active item in the queue. If there is no
+     * queue or a queue is not supported by the session this will be
+     * {@link MediaSession.QueueItem#UNKNOWN_ID}.
+     *
+     * @return The id of the currently active item in the queue or
+     *         {@link MediaSession.QueueItem#UNKNOWN_ID}.
+     */
+    public long getActiveQueueItemId() {
+        return mActiveItemId;
+    }
+
+    /**
      * Get the {@link PlaybackState} state for the given
      * {@link RemoteControlClient} state.
      *
@@ -716,7 +736,7 @@ public final class PlaybackState implements Parcelable {
         private long mActions;
         private CharSequence mErrorMessage;
         private long mUpdateTime;
-        private long mActiveItemId = MediaSession.Item.UNKNOWN_ID;
+        private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
 
         /**
          * Creates an initially empty state builder.
@@ -904,12 +924,12 @@ public final class PlaybackState implements Parcelable {
 
         /**
          * Set the active item in the play queue by specifying its id. The
-         * default value is {@link MediaSession.Item#UNKNOWN_ID}
+         * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
          *
          * @param id The id of the active item.
          * @return this
          */
-        public Builder setActiveItem(long id) {
+        public Builder setActiveQueueItemId(long id) {
             mActiveItemId = id;
             return this;
         }
@@ -1,9 +1,9 @@
 // Copyright 2014 Google Inc. All Rights Reserved.
 
-package android.media.browse;
+package android.service.media;
 
 import android.content.res.Configuration;
-import android.media.browse.IMediaBrowserServiceCallbacks;
+import android.service.media.IMediaBrowserServiceCallbacks;
 import android.net.Uri;
 import android.os.Bundle;
 
@@ -18,6 +18,4 @@ oneway interface IMediaBrowserService {
 
     void addSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks);
     void removeSubscription(in Uri uri, IMediaBrowserServiceCallbacks callbacks);
-    void loadIcon(in int seqNum, in Uri uri, int width, int height,
-            IMediaBrowserServiceCallbacks callbacks);
 }
\ No newline at end of file
@@ -1,6 +1,6 @@
 // Copyright 2014 Google Inc. All Rights Reserved.
 
-package android.media.browse;
+package android.service.media;
 
 import android.content.pm.ParceledListSlice;
 import android.graphics.Bitmap;
@@ -24,5 +24,4 @@ oneway interface IMediaBrowserServiceCallbacks {
     void onConnect(in Uri root, in MediaSession.Token session, in Bundle extras);
     void onConnectFailed();
     void onLoadChildren(in Uri uri, in ParceledListSlice list);
-    void onLoadIcon(int seqNum, in Bitmap bitmap);
 }
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.media.browse;
+package android.service.media;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -27,6 +27,8 @@ import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.media.browse.MediaBrowser;
+import android.media.browse.MediaBrowser.MediaItem;
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.Binder;
@@ -34,6 +36,9 @@ import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.service.media.IMediaBrowserService;
+import android.service.media.IMediaBrowserServiceCallbacks;
+import android.service.media.IMediaBrowserService.Stub;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -264,59 +269,6 @@ public abstract class MediaBrowserService extends Service {
                 }
             });
         }
-
-        @Override
-        public void loadIcon(final int seq, final Uri uri, final int width, final int height,
-                final IMediaBrowserServiceCallbacks callbacks) {
-            if (uri == null) {
-                throw new IllegalStateException("loadIcon sent null list for uri " + uri);
-            }
-            mHandler.post(new Runnable() {
-                @Override
-                public void run() {
-                    // In theory we could return a result to a new connection, but in practice
-                    // the other side in MediaBrowser uses a new IMediaBrowserServiceCallbacks
-                    // object every time it calls connect(), so as long as it does that we won't
-                    // see results sent for the wrong connection.
-                    final ConnectionRecord connection = mConnections.get(callbacks.asBinder());
-                    if (connection == null) {
-                        if (DBG) {
-                            Log.d(TAG, "Not loading bitmap for invalid connection. uri=" + uri);
-                        }
-                        return;
-                    }
-
-                    final Result<Bitmap> result = new Result<Bitmap>(uri) {
-                        @Override
-                        void onResultSent(Bitmap bitmap) {
-                            if (mConnections.get(connection.callbacks.asBinder()) != connection) {
-                                if (DBG) {
-                                    Log.d(TAG, "Not sending onLoadIcon result for connection"
-                                            + " that has been disconnected. pkg=" + connection.pkg
-                                            + " uri=" + uri);
-                                }
-                                return;
-                            }
-
-                            try {
-                                callbacks.onLoadIcon(seq, bitmap);
-                            } catch (RemoteException e) {
-                                // The other side is in the process of crashing.
-                                Log.w(TAG, "RemoteException in calling onLoadIcon", e);
-                            }
-                        }
-                    };
-
-                    onLoadIcon(uri, width, height, result);
-
-                    if (!result.isDone()) {
-                        throw new IllegalStateException("onLoadIcon must call detach() or"
-                                + " sendResult() before returning for package=" + connection.pkg
-                                + " uri=" + uri);
-                    }
-                }
-            });
-        }
     }
 
     @Override
@@ -372,26 +324,7 @@ public abstract class MediaBrowserService extends Service {
      * @return The list of children, or null if the uri is invalid.
      */
     public abstract void onLoadChildren(@NonNull Uri parentUri,
-            @NonNull Result<List<MediaBrowserItem>> result);
-
-    /**
-     * Called to get the icon of a particular media item.
-     * <p>
-     * Implementations must call result.{@link Result#sendResult result.sendResult} with the bitmap.
-     * If loading the bitmap 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.
-     *
-     * @param uri The uri of the media item.
-     * @param width The requested width of the icon in dp.
-     * @param height The requested height of the icon in dp.
-     *
-     * @return The file descriptor of the icon, which may then be loaded
-     *          using a bitmap factory, or null if the item does not have an icon.
-     */
-    public abstract void onLoadIcon(@NonNull Uri uri, int width, int height,
-            @NonNull Result<Bitmap> result);
+            @NonNull Result<List<MediaBrowser.MediaItem>> result);
 
     /**
      * Call to set the media session.
@@ -478,9 +411,11 @@ public abstract class MediaBrowserService extends Service {
      * Callers must make sure that this connection is still connected.
      */
     private void performLoadChildren(final Uri uri, final ConnectionRecord connection) {
-        final Result<List<MediaBrowserItem>> result = new Result<List<MediaBrowserItem>>(uri) {
+        final Result<List<MediaBrowser.MediaItem>> result
+ = new Result<List<MediaBrowser.MediaItem>>(
+                uri) {
             @Override
-            void onResultSent(List<MediaBrowserItem> list) {
+            void onResultSent(List<MediaBrowser.MediaItem> list) {
                 if (list == null) {
                     throw new IllegalStateException("onLoadChildren sent null list for uri " + uri);
                 }
@@ -492,7 +427,7 @@ public abstract class MediaBrowserService extends Service {
                     return;
                 }
 
-                final ParceledListSlice<MediaBrowserItem> pls = new ParceledListSlice(list);
+                final ParceledListSlice<MediaBrowser.MediaItem> pls = new ParceledListSlice(list);
                 try {
                     connection.callbacks.onLoadChildren(uri, pls);
                 } catch (RemoteException ex) {
index 978a9f4..0da2cfa 100644 (file)
@@ -23,6 +23,7 @@ import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.media.AudioManager;
 import android.media.AudioManagerInternal;
+import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.Rating;
 import android.media.VolumeProvider;
@@ -441,7 +442,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
 
     private String getShortMetadataString() {
         int fields = mMetadata == null ? 0 : mMetadata.size();
-        MediaMetadata.Description description = mMetadata == null ? null : mMetadata
+        MediaDescription description = mMetadata == null ? null : mMetadata
                 .getDescription();
         return "size=" + fields + ", description=" + description;
     }
@@ -820,9 +821,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
             }
         }
 
-        public void playUri(Uri uri, Bundle extras) {
+        public void playFromMediaId(String mediaId, Bundle extras) {
             try {
-                mCb.onPlayUri(uri, extras);
+                mCb.onPlayFromMediaId(mediaId, extras);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Remote failure in playUri.", e);
             }
@@ -1042,8 +1043,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
         }
 
         @Override
-        public void playUri(Uri uri, Bundle extras) throws RemoteException {
-            mSessionCb.playUri(uri, extras);
+        public void playFromMediaId(String mediaId, Bundle extras) throws RemoteException {
+            mSessionCb.playFromMediaId(mediaId, extras);
         }
 
         @Override
@@ -1052,7 +1053,7 @@ public class MediaSessionRecord implements IBinder.DeathRecipient {
         }
 
         @Override
-        public void skipToTrack(long id) {
+        public void skipToQueueItem(long id) {
             mSessionCb.skipToTrack(id);
         }
 
index a5bcda5..d1172ac 100644 (file)
@@ -12,6 +12,7 @@ import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.graphics.Bitmap;
+import android.media.MediaDescription;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
@@ -185,10 +186,10 @@ public class NotificationHelper extends BroadcastReceiver {
             text = "Empty metadata!";
             art = null;
         } else {
-            MediaMetadata.Description description = mMetadata.getDescription();
+            MediaDescription description = mMetadata.getDescription();
             title = description.getTitle();
             text = description.getSubtitle();
-            art = description.getIcon();
+            art = description.getIconBitmap();
         }
 
         String playPauseLabel = "";