From 3625bf72cb8bcf3c7f8f8cd8d708d7206824cc62 Mon Sep 17 00:00:00 2001 From: RoboErik Date: Wed, 27 Aug 2014 16:03:19 -0700 Subject: [PATCH] Update to MediaBrowser APIs per council feedback Does all the updates in the bug except the loadIcon/loadBitmap methods, which are removed per feedback from Sharkey. bug:17205016 Change-Id: Ie84d4d25a59c6985ce16972c26c8d1e5c02ff5c9 --- Android.mk | 4 +- api/current.txt | 159 +++++------ media/java/android/media/MediaDescription.aidl | 18 ++ media/java/android/media/MediaDescription.java | 276 ++++++++++++++++++ media/java/android/media/MediaMetadata.java | 139 +++------ media/java/android/media/browse/MediaBrowser.java | 307 +++++++++----------- .../android/media/browse/MediaBrowserItem.java | 313 --------------------- .../android/media/session/ISessionCallback.aidl | 2 +- .../android/media/session/ISessionController.aidl | 4 +- .../android/media/session/MediaController.java | 27 +- media/java/android/media/session/MediaSession.aidl | 2 +- media/java/android/media/session/MediaSession.java | 161 ++++------- .../java/android/media/session/PlaybackState.java | 56 ++-- .../media}/IMediaBrowserService.aidl | 6 +- .../media}/IMediaBrowserServiceCallbacks.aidl | 3 +- .../media}/MediaBrowserService.java | 89 +----- .../android/server/media/MediaSessionRecord.java | 13 +- .../com/android/onemedia/NotificationHelper.java | 5 +- 18 files changed, 674 insertions(+), 910 deletions(-) create mode 100644 media/java/android/media/MediaDescription.aidl create mode 100644 media/java/android/media/MediaDescription.java delete mode 100644 media/java/android/media/browse/MediaBrowserItem.java rename media/java/android/{media/browse => service/media}/IMediaBrowserService.aidl (76%) rename media/java/android/{media/browse => service/media}/IMediaBrowserServiceCallbacks.aidl (92%) rename media/java/android/{media/browse => service/media}/MediaBrowserService.java (81%) diff --git a/Android.mk b/Android.mk index 3edaefc4dd96..35bb66c43d34 100644 --- a/Android.mk +++ b/Android.mk @@ -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 \ diff --git a/api/current.txt b/api/current.txt index 8a03269551ee..829601d39647 100644 --- a/api/current.txt +++ b/api/current.txt @@ -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); - 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>); - method public abstract void onLoadIcon(android.net.Uri, int, int, android.media.browse.MediaBrowserService.Result); - 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); + 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 getQueue(); + method public java.util.List 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); + method public void onQueueChanged(java.util.List); 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); + method public void setQueue(java.util.List); 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 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>); + 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 index 000000000000..6f934f75aa28 --- /dev/null +++ b/media/java/android/media/MediaDescription.aidl @@ -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 index 000000000000..4399c0db4e89 --- /dev/null +++ b/media/java/android/media/MediaDescription.java @@ -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 CREATOR = + new Parcelable.Creator() { + @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); + } + } +} diff --git a/media/java/android/media/MediaMetadata.java b/media/java/android/media/MediaMetadata.java index 74f7a966aef5..b4e603394c2d 100644 --- a/media/java/android/media/MediaMetadata.java +++ b/media/java/android/media/MediaMetadata.java @@ -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; - } - } - } diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java index 1c6d81fbfe4a..debaf45585cc 100644 --- a/media/java/android/media/browse/MediaBrowser.java +++ b/media/java/android/media/browse/MediaBrowser.java @@ -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 mSubscriptions = new ArrayMap(); - private final SparseArray mIconRequests = - new SparseArray(); 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 data = list.getList(); + List 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. + *

+ * The Uri of this item may be passed to link android.media.session.MediaController#play(Uri) + * to start playing it. + *

+ */ + 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 CREATOR = + new Parcelable.Creator() { + @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 children) { + public boolean isBrowsable() { + return (mFlags & FLAG_BROWSABLE) != 0; } /** - * Called when the Uri doesn't exist or other errors in subscribing. - *

- * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe} - * called, because some errors may heal themselves. - *

+ * 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 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(); + 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 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. + *

+ * If this is called, the subscription remains until {@link MediaBrowser#unsubscribe} + * called, because some errors may heal themselves. + *

*/ - public List 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 index 47ec46b2d52e..000000000000 --- a/media/java/android/media/browse/MediaBrowserItem.java +++ /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. - *

- * The Uri of this item may be passed to link android.media.session.MediaController#play(Uri) - * to start playing it. - *

- */ - 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 CREATOR = - new Parcelable.Creator() { - @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. - *

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

- */ - public @NonNull Builder setIconUri(@Nullable Uri iconUri) { - mIconUri = iconUri; - return this; - } - - /** - * Sets the resource id of the icon. - *

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

- */ - 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); - } - } -} - diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl index 99111293efa5..49087b03f748 100644 --- a/media/java/android/media/session/ISessionCallback.aidl +++ b/media/java/android/media/session/ISessionCallback.aidl @@ -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(); diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 6b804778a3e5..d684688f027e 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -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(); diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index d7baaa9b92b5..9641f83c8a33 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -173,7 +173,7 @@ public final class MediaController { * * @return The current play queue or null. */ - public @Nullable List getQueue() { + public @Nullable List 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 queue) { + public void onQueueChanged(@Nullable List 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 queue = parceledQueue.getList(); + List 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) msg.obj); + mCallback.onQueueChanged((List) msg.obj); break; case MSG_UPDATE_QUEUE_TITLE: mCallback.onQueueTitleChanged((CharSequence) msg.obj); diff --git a/media/java/android/media/session/MediaSession.aidl b/media/java/android/media/session/MediaSession.aidl index 0ad58c43584b..f657cef76bcd 100644 --- a/media/java/android/media/session/MediaSession.aidl +++ b/media/java/android/media/session/MediaSession.aidl @@ -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 diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 1670097467a9..f70b217f06cb 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -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 queue) { + public void setQueue(@Nullable List queue) { try { - mBinder.setQueue(new ParceledListSlice(queue)); + mBinder.setQueue(new ParceledListSlice(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 CREATOR - = new Creator() { + public static final Creator CREATOR = new Creator() { @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; diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index 2ca97ddc5da8..267d1ff9457b 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -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; } diff --git a/media/java/android/media/browse/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl similarity index 76% rename from media/java/android/media/browse/IMediaBrowserService.aidl rename to media/java/android/service/media/IMediaBrowserService.aidl index 8acd724892fc..2631ddde0111 100644 --- a/media/java/android/media/browse/IMediaBrowserService.aidl +++ b/media/java/android/service/media/IMediaBrowserService.aidl @@ -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 diff --git a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl similarity index 92% rename from media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl rename to media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl index 06fabcc810b6..7702a50b2830 100644 --- a/media/java/android/media/browse/IMediaBrowserServiceCallbacks.aidl +++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl @@ -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); } diff --git a/media/java/android/media/browse/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java similarity index 81% rename from media/java/android/media/browse/MediaBrowserService.java rename to media/java/android/service/media/MediaBrowserService.java index 99126c98b87a..4d6fd7b526e3 100644 --- a/media/java/android/media/browse/MediaBrowserService.java +++ b/media/java/android/service/media/MediaBrowserService.java @@ -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 result = new Result(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> result); - - /** - * Called to get the icon of a particular media item. - *

- * 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 result); + @NonNull Result> 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> result = new Result>(uri) { + final Result> result + = new Result>( + uri) { @Override - void onResultSent(List list) { + void onResultSent(List 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 pls = new ParceledListSlice(list); + final ParceledListSlice pls = new ParceledListSlice(list); try { connection.callbacks.onLoadChildren(uri, pls); } catch (RemoteException ex) { diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 978a9f49379d..0da2cfa8e19f 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -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); } diff --git a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java index a5bcda516b01..d1172ace49a9 100644 --- a/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java +++ b/tests/OneMedia/src/com/android/onemedia/NotificationHelper.java @@ -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 = ""; -- 2.11.0