Remove MediaComponents
Test: build
Change-Id: I50da7f34858a4739777d84abdde8a502537bf57e
diff --git a/packages/MediaComponents/apex/Android.bp b/packages/MediaComponents/apex/Android.bp
deleted file mode 100644
index d89eb77..0000000
--- a/packages/MediaComponents/apex/Android.bp
+++ /dev/null
@@ -1,41 +0,0 @@
-filegroup {
- name: "media_aidl",
- srcs: [
- "java/android/media/**/*.aidl",
- "java/android/service/**/*.aidl",
- ],
- exclude_srcs: [
- // Exclude these aidls to avoid errors such as
- // "Refusing to generate code with unstructured parcelables."
- "java/android/media/MediaDescription.aidl",
- "java/android/media/MediaMetadata.aidl",
- // TODO(insun): check why MediaParceledListSlice.aidl should be added here
- "java/android/media/MediaParceledListSlice.aidl",
- "java/android/media/Rating.aidl",
- "java/android/media/browse/MediaBrowser.aidl",
- "java/android/media/session/MediaSession.aidl",
- "java/android/media/session/ParcelableVolumeInfo.aidl",
- "java/android/media/session/PlaybackState.aidl",
- ],
-}
-
-java_library {
- name: "media",
- installable: true,
- sdk_version: "system_current",
- srcs: [
- "java/android/media/**/*.java",
- "java/android/service/**/*.java",
- ":media_aidl",
- ":framework-media-annotation-srcs",
- ],
- aidl: {
- local_include_dirs: ["java"],
- include_dirs: [
- "frameworks/base/core/java",
- // for android.graphics.Bitmap
- // from IMediaBrowserServiceCallback
- "frameworks/base/graphics/java",
- ],
- },
-}
diff --git a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl b/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
deleted file mode 100644
index e4a4a42..0000000
--- a/packages/MediaComponents/apex/java/android/media/IRemoteVolumeController.aidl
+++ /dev/null
@@ -1,32 +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;
-
-import android.media.session.ISessionController;
-
-/**
- * AIDL for the MediaSessionService to report interesting events on remote playback
- * to a volume control dialog. See also IVolumeController for the AudioService half.
- * TODO add in better support for multiple remote sessions.
- * @hide
- */
-oneway interface IRemoteVolumeController {
- void remoteVolumeChanged(ISessionController session, int flags);
- // sets the default session to use with the slider, replaces remoteSliderVisibility
- // on IVolumeController
- void updateRemoteController(ISessionController session);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl b/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
deleted file mode 100644
index c83a19e..0000000
--- a/packages/MediaComponents/apex/java/android/media/ISessionTokensListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.os.Bundle;
-
-/**
- * Listens for changes to the list of session tokens.
- * @hide
- */
-oneway interface ISessionTokensListener {
- void onSessionTokensChanged(in List<Bundle> tokens);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl b/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
deleted file mode 100644
index 6f934f7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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/packages/MediaComponents/apex/java/android/media/MediaDescription.java b/packages/MediaComponents/apex/java/android/media/MediaDescription.java
deleted file mode 100644
index 31079e5..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaDescription.java
+++ /dev/null
@@ -1,383 +0,0 @@
-package android.media;
-
-import android.annotation.Nullable;
-import android.graphics.Bitmap;
-import android.media.browse.MediaBrowser;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-
-/**
- * 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;
- /**
- * A Uri to identify this content.
- */
- private final Uri mMediaUri;
-
- /**
- * Used as a long extra field to indicate the bluetooth folder type of the media item as
- * specified in the section 6.10.2.2 of the Bluetooth AVRCP 1.5. This is valid only for
- * {@link MediaBrowser.MediaItem} with {@link MediaBrowser.MediaItem#FLAG_BROWSABLE}. The value
- * should be one of the following:
- * <ul>
- * <li>{@link #BT_FOLDER_TYPE_MIXED}</li>
- * <li>{@link #BT_FOLDER_TYPE_TITLES}</li>
- * <li>{@link #BT_FOLDER_TYPE_ALBUMS}</li>
- * <li>{@link #BT_FOLDER_TYPE_ARTISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_GENRES}</li>
- * <li>{@link #BT_FOLDER_TYPE_PLAYLISTS}</li>
- * <li>{@link #BT_FOLDER_TYPE_YEARS}</li>
- * </ul>
- *
- * @see #getExtras()
- */
- public static final String EXTRA_BT_FOLDER_TYPE = "android.media.extra.BT_FOLDER_TYPE";
-
- /**
- * The type of folder that is unknown or contains media elements of mixed types as specified in
- * the section 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_MIXED = 0;
-
- /**
- * The type of folder that contains media elements only as specified in the section 6.10.2.2 of
- * the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_TITLES = 1;
-
- /**
- * The type of folder that contains folders categorized by album as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ALBUMS = 2;
-
- /**
- * The type of folder that contains folders categorized by artist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_ARTISTS = 3;
-
- /**
- * The type of folder that contains folders categorized by genre as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_GENRES = 4;
-
- /**
- * The type of folder that contains folders categorized by playlist as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_PLAYLISTS = 5;
-
- /**
- * The type of folder that contains folders categorized by year as specified in the section
- * 6.10.2.2 of the Bluetooth AVRCP 1.5.
- */
- public static final long BT_FOLDER_TYPE_YEARS = 6;
-
- private MediaDescription(String mediaId, CharSequence title, CharSequence subtitle,
- CharSequence description, Bitmap icon, Uri iconUri, Bundle extras, Uri mediaUri) {
- mMediaId = mediaId;
- mTitle = title;
- mSubtitle = subtitle;
- mDescription = description;
- mIcon = icon;
- mIconUri = iconUri;
- mExtras = extras;
- mMediaUri = mediaUri;
- }
-
- private MediaDescription(Parcel in) {
- mMediaId = in.readString();
- mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mSubtitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mIcon = in.readParcelable(null);
- mIconUri = in.readParcelable(null);
- mExtras = in.readBundle();
- mMediaUri = in.readParcelable(null);
- }
-
- /**
- * 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;
- }
-
- /**
- * Returns a Uri representing this content or null.
- *
- * @return A media Uri or null.
- */
- public @Nullable Uri getMediaUri() {
- return mMediaUri;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mMediaId);
- TextUtils.writeToParcel(mTitle, dest, 0);
- TextUtils.writeToParcel(mSubtitle, dest, 0);
- TextUtils.writeToParcel(mDescription, dest, 0);
- dest.writeParcelable(mIcon, flags);
- dest.writeParcelable(mIconUri, flags);
- dest.writeBundle(mExtras);
- dest.writeParcelable(mMediaUri, flags);
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
-
- if (!(o instanceof MediaDescription)){
- return false;
- }
-
- final MediaDescription d = (MediaDescription) o;
-
- if (!String.valueOf(mTitle).equals(String.valueOf(d.mTitle))) {
- return false;
- }
-
- if (!String.valueOf(mSubtitle).equals(String.valueOf(d.mSubtitle))) {
- return false;
- }
-
- if (!String.valueOf(mDescription).equals(String.valueOf(d.mDescription))) {
- return false;
- }
-
- return true;
- }
-
- @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;
- private Uri mMediaUri;
-
- /**
- * 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;
- }
-
- /**
- * Sets the media uri.
- *
- * @param mediaUri The content's {@link Uri} for the item or null.
- * @return this
- */
- public Builder setMediaUri(@Nullable Uri mediaUri) {
- mMediaUri = mediaUri;
- return this;
- }
-
- public MediaDescription build() {
- return new MediaDescription(mMediaId, mTitle, mSubtitle, mDescription, mIcon, mIconUri,
- mExtras, mMediaUri);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl b/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
deleted file mode 100644
index 66ee483..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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 MediaMetadata;
diff --git a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java b/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
deleted file mode 100644
index adfd20b..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaMetadata.java
+++ /dev/null
@@ -1,941 +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;
-
-import android.annotation.NonNull;
-import android.annotation.StringDef;
-import android.annotation.UnsupportedAppUsage;
-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.Parcel;
-import android.os.Parcelable;
-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.util.Set;
-import java.util.Objects;
-
-/**
- * Contains metadata about an item, such as the title, artist, etc.
- */
-public final class MediaMetadata implements Parcelable {
- private static final String TAG = "MediaMetadata";
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_TITLE,
- METADATA_KEY_ARTIST,
- METADATA_KEY_ALBUM,
- METADATA_KEY_AUTHOR,
- METADATA_KEY_WRITER,
- METADATA_KEY_COMPOSER,
- METADATA_KEY_COMPILATION,
- METADATA_KEY_DATE,
- METADATA_KEY_GENRE,
- METADATA_KEY_ALBUM_ARTIST,
- METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI,
- METADATA_KEY_DISPLAY_TITLE,
- METADATA_KEY_DISPLAY_SUBTITLE,
- METADATA_KEY_DISPLAY_DESCRIPTION,
- METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_MEDIA_ID,
- METADATA_KEY_MEDIA_URI,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TextKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_DURATION,
- METADATA_KEY_YEAR,
- METADATA_KEY_TRACK_NUMBER,
- METADATA_KEY_NUM_TRACKS,
- METADATA_KEY_DISC_NUMBER,
- METADATA_KEY_BT_FOLDER_TYPE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LongKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_ART,
- METADATA_KEY_ALBUM_ART,
- METADATA_KEY_DISPLAY_ICON,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface BitmapKey {}
-
- /**
- * @hide
- */
- @StringDef(prefix = { "METADATA_KEY_" }, value = {
- METADATA_KEY_USER_RATING,
- METADATA_KEY_RATING,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RatingKey {}
-
- /**
- * The title of the media.
- */
- public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
-
- /**
- * The artist of the media.
- */
- public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST";
-
- /**
- * The duration of the media in ms. A negative duration indicates that the
- * duration is unknown (or infinite).
- */
- public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION";
-
- /**
- * The album title for the media.
- */
- public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM";
-
- /**
- * The author of the media.
- */
- public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR";
-
- /**
- * The writer of the media.
- */
- public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER";
-
- /**
- * The composer of the media.
- */
- public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER";
-
- /**
- * The compilation status of the media.
- */
- public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION";
-
- /**
- * The date the media was created or published. The format is unspecified
- * but RFC 3339 is recommended.
- */
- public static final String METADATA_KEY_DATE = "android.media.metadata.DATE";
-
- /**
- * The year the media was created or published as a long.
- */
- public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR";
-
- /**
- * The genre of the media.
- */
- public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE";
-
- /**
- * The track number for the media.
- */
- public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER";
-
- /**
- * The number of tracks in the media's original source.
- */
- public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS";
-
- /**
- * The disc number for the media's original source.
- */
- public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER";
-
- /**
- * The artist for the album of the media's original source.
- */
- public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST";
-
- /**
- * The artwork for the media as a {@link Bitmap}.
- * <p>
- * The artwork should be relatively small and may be scaled down by the
- * system if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_ART_URI} should be used instead.
- */
- public static final String METADATA_KEY_ART = "android.media.metadata.ART";
-
- /**
- * 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}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI";
-
- /**
- * The artwork for the album of the media's original source as a
- * {@link Bitmap}.
- * <p>
- * The artwork should be relatively small and may be scaled down by the
- * system if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead.
- */
- 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
- * formatted String. The artwork can be loaded using a combination of
- * {@link ContentResolver#openInputStream} and
- * {@link BitmapFactory#decodeStream}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI";
-
- /**
- * The user's rating for the media.
- *
- * @see Rating
- */
- public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING";
-
- /**
- * The overall rating for the media.
- *
- * @see Rating
- */
- public static final String METADATA_KEY_RATING = "android.media.metadata.RATING";
-
- /**
- * A title that is suitable for display to the user. This will generally be
- * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats.
- * When displaying media described by this metadata this should be preferred
- * if present.
- */
- public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE";
-
- /**
- * A subtitle that is suitable for display to the user. When displaying a
- * second line for media described by this metadata this should be preferred
- * to other fields if present.
- */
- public static final String METADATA_KEY_DISPLAY_SUBTITLE
- = "android.media.metadata.DISPLAY_SUBTITLE";
-
- /**
- * A description that is suitable for display to the user. When displaying
- * more information for media described by this metadata this should be
- * preferred to other fields if present.
- */
- public static final String METADATA_KEY_DISPLAY_DESCRIPTION
- = "android.media.metadata.DISPLAY_DESCRIPTION";
-
- /**
- * An icon or thumbnail that is suitable for display to the user. When
- * displaying an icon for media described by this metadata this should be
- * preferred to other fields if present. This must be a {@link Bitmap}.
- * <p>
- * The icon should be relatively small and may be scaled down by the system
- * if it is too large. For higher resolution artwork
- * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead.
- */
- public static final String METADATA_KEY_DISPLAY_ICON
- = "android.media.metadata.DISPLAY_ICON";
-
- /**
- * 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}.
- * <p>
- * For the best results, Uris should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork through
- * {@link ContentResolver#openTypedAssetFileDescriptor(Uri, String, Bundle)}.
- */
- 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";
-
- /**
- * A Uri formatted String representing the content. This value is specific to the
- * service providing the content. It may be used with
- * {@link MediaController.TransportControls#playFromUri(Uri, Bundle)}
- * to initiate playback when provided by a {@link MediaBrowser} connected to
- * the same app.
- */
- public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI";
-
- /**
- * The bluetooth folder type of the media specified in the section 6.10.2.2 of the Bluetooth
- * AVRCP 1.5. It should be one of the following:
- * <ul>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_MIXED}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_TITLES}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_ALBUMS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_ARTISTS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_GENRES}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_PLAYLISTS}</li>
- * <li>{@link MediaDescription#BT_FOLDER_TYPE_YEARS}</li>
- * </ul>
- */
- public static final String METADATA_KEY_BT_FOLDER_TYPE
- = "android.media.metadata.BT_FOLDER_TYPE";
-
- private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
- METADATA_KEY_TITLE,
- METADATA_KEY_ARTIST,
- METADATA_KEY_ALBUM,
- METADATA_KEY_ALBUM_ARTIST,
- METADATA_KEY_WRITER,
- METADATA_KEY_AUTHOR,
- METADATA_KEY_COMPOSER
- };
-
- private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
- METADATA_KEY_DISPLAY_ICON,
- METADATA_KEY_ART,
- METADATA_KEY_ALBUM_ART
- };
-
- private static final @TextKey String[] PREFERRED_URI_ORDER = {
- METADATA_KEY_DISPLAY_ICON_URI,
- METADATA_KEY_ART_URI,
- METADATA_KEY_ALBUM_ART_URI
- };
-
- private static final int METADATA_TYPE_INVALID = -1;
- private static final int METADATA_TYPE_LONG = 0;
- private static final int METADATA_TYPE_TEXT = 1;
- private static final int METADATA_TYPE_BITMAP = 2;
- private static final int METADATA_TYPE_RATING = 3;
- private static final ArrayMap<String, Integer> METADATA_KEYS_TYPE;
-
- static {
- METADATA_KEYS_TYPE = new ArrayMap<String, Integer>();
- METADATA_KEYS_TYPE.put(METADATA_KEY_TITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ARTIST, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DURATION, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_AUTHOR, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_WRITER, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_COMPOSER, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_COMPILATION, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DATE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_YEAR, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_GENRE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_TRACK_NUMBER, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_NUM_TRACKS, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISC_NUMBER, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ARTIST, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ART, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ART_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_ALBUM_ART_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_USER_RATING, METADATA_TYPE_RATING);
- METADATA_KEYS_TYPE.put(METADATA_KEY_RATING, METADATA_TYPE_RATING);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_TITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_SUBTITLE, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON, METADATA_TYPE_BITMAP);
- METADATA_KEYS_TYPE.put(METADATA_KEY_DISPLAY_ICON_URI, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_BT_FOLDER_TYPE, METADATA_TYPE_LONG);
- METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_ID, METADATA_TYPE_TEXT);
- METADATA_KEYS_TYPE.put(METADATA_KEY_MEDIA_URI, METADATA_TYPE_TEXT);
- }
-
- private static final SparseArray<String> EDITOR_KEY_MAPPING;
-
- static {
- EDITOR_KEY_MAPPING = new SparseArray<String>();
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.BITMAP_KEY_ARTWORK, METADATA_KEY_ART);
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_OTHERS, METADATA_KEY_RATING);
- EDITOR_KEY_MAPPING.put(MediaMetadataEditor.RATING_KEY_BY_USER, METADATA_KEY_USER_RATING);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUM, METADATA_KEY_ALBUM);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
- METADATA_KEY_ALBUM_ARTIST);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_ARTIST, METADATA_KEY_ARTIST);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_AUTHOR, METADATA_KEY_AUTHOR);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
- METADATA_KEY_TRACK_NUMBER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPOSER, METADATA_KEY_COMPOSER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_COMPILATION,
- METADATA_KEY_COMPILATION);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DATE, METADATA_KEY_DATE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
- METADATA_KEY_DISC_NUMBER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_DURATION, METADATA_KEY_DURATION);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_GENRE, METADATA_KEY_GENRE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
- METADATA_KEY_NUM_TRACKS);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_TITLE, METADATA_KEY_TITLE);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_WRITER, METADATA_KEY_WRITER);
- EDITOR_KEY_MAPPING.put(MediaMetadataRetriever.METADATA_KEY_YEAR, METADATA_KEY_YEAR);
- }
-
- private final Bundle mBundle;
- private MediaDescription mDescription;
-
- private MediaMetadata(Bundle bundle) {
- mBundle = new Bundle(bundle);
- }
-
- private MediaMetadata(Parcel in) {
- mBundle = in.readBundle();
- }
-
- /**
- * Returns true if the given key is contained in the metadata
- *
- * @param key a String key
- * @return true if the key exists in this metadata, false otherwise
- */
- public boolean containsKey(String key) {
- return mBundle.containsKey(key);
- }
-
- /**
- * Returns the value associated with the given key, or null if no mapping of
- * the desired type exists for the given key or a null value is explicitly
- * associated with the key.
- *
- * @param key The key the value is stored under
- * @return a CharSequence value, or null
- */
- public CharSequence getText(@TextKey String key) {
- return mBundle.getCharSequence(key);
- }
-
- /**
- * Returns the text value associated with the given key as a String, or null
- * if no mapping of the desired type exists for the given key or a null
- * value is explicitly associated with the key. This is equivalent to
- * calling {@link #getText getText().toString()} if the value is not null.
- *
- * @param key The key the value is stored under
- * @return a String value, or null
- */
- public String getString(@TextKey String key) {
- CharSequence text = getText(key);
- if (text != null) {
- return text.toString();
- }
- return null;
- }
-
- /**
- * Returns the value associated with the given key, or 0L if no long exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return a long value
- */
- public long getLong(@LongKey String key) {
- return mBundle.getLong(key, 0);
- }
-
- /**
- * Returns a {@link Rating} for the given key or null if no rating exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return A {@link Rating} or null
- */
- public Rating getRating(@RatingKey String key) {
- Rating rating = null;
- try {
- rating = mBundle.getParcelable(key);
- } catch (Exception e) {
- // ignore, value was not a bitmap
- Log.w(TAG, "Failed to retrieve a key as Rating.", e);
- }
- return rating;
- }
-
- /**
- * Returns a {@link Bitmap} for the given key or null if no bitmap exists
- * for the given key.
- *
- * @param key The key the value is stored under
- * @return A {@link Bitmap} or null
- */
- public Bitmap getBitmap(@BitmapKey String key) {
- Bitmap bmp = null;
- try {
- bmp = mBundle.getParcelable(key);
- } catch (Exception e) {
- // ignore, value was not a bitmap
- Log.w(TAG, "Failed to retrieve a key as Bitmap.", e);
- }
- return bmp;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeBundle(mBundle);
- }
-
- /**
- * Returns the number of fields in this metadata.
- *
- * @return The number of fields in the metadata.
- */
- public int size() {
- return mBundle.size();
- }
-
- /**
- * Returns a Set containing the Strings used as keys in this metadata.
- *
- * @return a Set of String keys
- */
- public Set<String> keySet() {
- return mBundle.keySet();
- }
-
- /**
- * Returns a simple description of this metadata for display purposes.
- *
- * @return A simple description of this metadata.
- */
- 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;
-
- // First handle the case where display data is set already
- CharSequence displayText = getText(METADATA_KEY_DISPLAY_TITLE);
- if (!TextUtils.isEmpty(displayText)) {
- // If they have a display title use only display data, otherwise use
- // our best bets
- text[0] = displayText;
- text[1] = getText(METADATA_KEY_DISPLAY_SUBTITLE);
- text[2] = getText(METADATA_KEY_DISPLAY_DESCRIPTION);
- } else {
- // Use whatever fields we can
- int textIndex = 0;
- int keyIndex = 0;
- while (textIndex < text.length && keyIndex < PREFERRED_DESCRIPTION_ORDER.length) {
- CharSequence next = getText(PREFERRED_DESCRIPTION_ORDER[keyIndex++]);
- if (!TextUtils.isEmpty(next)) {
- // Fill in the next empty bit of text
- text[textIndex++] = next;
- }
- }
- }
-
- // Get the best art bitmap we can find
- for (int i = 0; i < PREFERRED_BITMAP_ORDER.length; i++) {
- Bitmap next = getBitmap(PREFERRED_BITMAP_ORDER[i]);
- if (next != null) {
- icon = next;
- break;
- }
- }
-
- // Get the best Uri we can find
- for (int i = 0; i < PREFERRED_URI_ORDER.length; i++) {
- String next = getString(PREFERRED_URI_ORDER[i]);
- if (!TextUtils.isEmpty(next)) {
- iconUri = Uri.parse(next);
- break;
- }
- }
-
- Uri mediaUri = null;
- String mediaUriStr = getString(METADATA_KEY_MEDIA_URI);
- if (!TextUtils.isEmpty(mediaUriStr)) {
- mediaUri = Uri.parse(mediaUriStr);
- }
-
- 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);
- bob.setMediaUri(mediaUri);
- if (mBundle.containsKey(METADATA_KEY_BT_FOLDER_TYPE)) {
- Bundle bundle = new Bundle();
- bundle.putLong(MediaDescription.EXTRA_BT_FOLDER_TYPE,
- getLong(METADATA_KEY_BT_FOLDER_TYPE));
- bob.setExtras(bundle);
- }
- mDescription = bob.build();
-
- return mDescription;
- }
-
- /**
- * Helper for getting the String key used by {@link MediaMetadata} from the
- * integer key that {@link MediaMetadataEditor} uses.
- *
- * @param editorKey The key used by the editor
- * @return The key used by this class or null if no mapping exists
- * @hide
- */
- @UnsupportedAppUsage
- public static String getKeyFromMetadataEditorKey(int editorKey) {
- return EDITOR_KEY_MAPPING.get(editorKey, null);
- }
-
- public static final Parcelable.Creator<MediaMetadata> CREATOR =
- new Parcelable.Creator<MediaMetadata>() {
- @Override
- public MediaMetadata createFromParcel(Parcel in) {
- return new MediaMetadata(in);
- }
-
- @Override
- public MediaMetadata[] newArray(int size) {
- return new MediaMetadata[size];
- }
- };
-
- /**
- * Compares the contents of this object to another MediaMetadata object. It
- * does not compare Bitmaps and Ratings as the media player can choose to
- * forgo these fields depending on how you retrieve the MediaMetadata.
- *
- * @param o The Metadata object to compare this object against
- * @return Whether or not the two objects have matching fields (excluding
- * Bitmaps and Ratings)
- */
- @Override
- public boolean equals(Object o) {
- if (o == this) {
- return true;
- }
-
- if (!(o instanceof MediaMetadata)) {
- return false;
- }
-
- final MediaMetadata m = (MediaMetadata) o;
-
- for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
- String key = METADATA_KEYS_TYPE.keyAt(i);
- switch (METADATA_KEYS_TYPE.valueAt(i)) {
- case METADATA_TYPE_TEXT:
- if (!Objects.equals(getString(key), m.getString(key))) {
- return false;
- }
- break;
- case METADATA_TYPE_LONG:
- if (getLong(key) != m.getLong(key)) {
- return false;
- }
- break;
- default:
- // Ignore ratings and bitmaps when comparing
- break;
- }
- }
-
- return true;
- }
-
- @Override
- public int hashCode() {
- int hashCode = 17;
-
- for (int i = 0; i < METADATA_KEYS_TYPE.size(); i++) {
- String key = METADATA_KEYS_TYPE.keyAt(i);
- switch (METADATA_KEYS_TYPE.valueAt(i)) {
- case METADATA_TYPE_TEXT:
- hashCode = 31 * hashCode + Objects.hash(getString(key));
- break;
- case METADATA_TYPE_LONG:
- hashCode = 31 * hashCode + Long.hashCode(getLong(key));
- break;
- default:
- // Ignore ratings and bitmaps when comparing
- break;
- }
- }
-
- return hashCode;
- }
-
- /**
- * Use to build MediaMetadata objects. The system defined metadata keys must
- * use the appropriate data type.
- */
- public static final class Builder {
- private final Bundle mBundle;
-
- /**
- * Create an empty Builder. Any field that should be included in the
- * {@link MediaMetadata} must be added.
- */
- public Builder() {
- mBundle = new Bundle();
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata} instance to set the
- * initial values. All fields in the source metadata will be included in
- * the new metadata. Fields can be overwritten by adding the same key.
- *
- * @param source
- */
- public Builder(MediaMetadata source) {
- mBundle = new Bundle(source.mBundle);
- }
-
- /**
- * Create a Builder using a {@link MediaMetadata} instance to set
- * initial values, but replace bitmaps with a scaled down copy if they
- * are larger than maxBitmapSize.
- *
- * @param source The original metadata to copy.
- * @param maxBitmapSize The maximum height/width for bitmaps contained
- * in the metadata.
- * @hide
- */
- public Builder(MediaMetadata source, int maxBitmapSize) {
- this(source);
- for (String key : mBundle.keySet()) {
- Object value = mBundle.get(key);
- if (value != null && value instanceof Bitmap) {
- Bitmap bmp = (Bitmap) value;
- if (bmp.getHeight() > maxBitmapSize || bmp.getWidth() > maxBitmapSize) {
- putBitmap(key, scaleBitmap(bmp, maxBitmapSize));
- }
- }
- }
- }
-
- /**
- * Put a CharSequence value into the metadata. Custom keys may be used,
- * but if the METADATA_KEYs defined in this class are used they may only
- * be one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The CharSequence value to store
- * @return The Builder to allow chaining
- */
- public Builder putText(@TextKey String key, CharSequence value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a CharSequence");
- }
- }
- mBundle.putCharSequence(key, value);
- return this;
- }
-
- /**
- * Put a String value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_TITLE}</li>
- * <li>{@link #METADATA_KEY_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ALBUM}</li>
- * <li>{@link #METADATA_KEY_AUTHOR}</li>
- * <li>{@link #METADATA_KEY_WRITER}</li>
- * <li>{@link #METADATA_KEY_COMPOSER}</li>
- * <li>{@link #METADATA_KEY_DATE}</li>
- * <li>{@link #METADATA_KEY_GENRE}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ARTIST}</li>
- * <li>{@link #METADATA_KEY_ART_URI}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART_URI}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_TITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_SUBTITLE}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_DESCRIPTION}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON_URI}</li>
- * </ul>
- * <p>
- * Uris for artwork should use the content:// style and support
- * {@link ContentResolver#EXTRA_SIZE} for retrieving scaled artwork
- * through {@link ContentResolver#openTypedAssetFileDescriptor(Uri,
- * String, Bundle)}.
- *
- * @param key The key for referencing this value
- * @param value The String value to store
- * @return The Builder to allow chaining
- */
- public Builder putString(@TextKey String key, String value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a String");
- }
- }
- mBundle.putCharSequence(key, value);
- return this;
- }
-
- /**
- * Put a long value into the metadata. Custom keys may be used, but if
- * the METADATA_KEYs defined in this class are used they may only be one
- * of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_DURATION}</li>
- * <li>{@link #METADATA_KEY_TRACK_NUMBER}</li>
- * <li>{@link #METADATA_KEY_NUM_TRACKS}</li>
- * <li>{@link #METADATA_KEY_DISC_NUMBER}</li>
- * <li>{@link #METADATA_KEY_YEAR}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The long value to store
- * @return The Builder to allow chaining
- */
- public Builder putLong(@LongKey String key, long value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a long");
- }
- }
- mBundle.putLong(key, value);
- return this;
- }
-
- /**
- * Put a {@link Rating} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_RATING}</li>
- * <li>{@link #METADATA_KEY_USER_RATING}</li>
- * </ul>
- *
- * @param key The key for referencing this value
- * @param value The Rating value to store
- * @return The Builder to allow chaining
- */
- public Builder putRating(@RatingKey String key, Rating value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a Rating");
- }
- }
- mBundle.putParcelable(key, value);
- return this;
- }
-
- /**
- * Put a {@link Bitmap} into the metadata. Custom keys may be used, but
- * if the METADATA_KEYs defined in this class are used they may only be
- * one of the following:
- * <ul>
- * <li>{@link #METADATA_KEY_ART}</li>
- * <li>{@link #METADATA_KEY_ALBUM_ART}</li>
- * <li>{@link #METADATA_KEY_DISPLAY_ICON}</li>
- * </ul>
- * <p>
- * Large bitmaps may be scaled down by the system when
- * {@link android.media.session.MediaSession#setMetadata} is called.
- * To pass full resolution images {@link Uri Uris} should be used with
- * {@link #putString}.
- *
- * @param key The key for referencing this value
- * @param value The Bitmap to store
- * @return The Builder to allow chaining
- */
- public Builder putBitmap(@BitmapKey String key, Bitmap value) {
- if (METADATA_KEYS_TYPE.containsKey(key)) {
- if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
- throw new IllegalArgumentException("The " + key
- + " key cannot be used to put a Bitmap");
- }
- }
- mBundle.putParcelable(key, value);
- return this;
- }
-
- /**
- * Creates a {@link MediaMetadata} instance with the specified fields.
- *
- * @return The new MediaMetadata instance
- */
- public MediaMetadata build() {
- return new MediaMetadata(mBundle);
- }
-
- private Bitmap scaleBitmap(Bitmap bmp, int maxSize) {
- float maxSizeF = maxSize;
- float widthScale = maxSizeF / bmp.getWidth();
- float heightScale = maxSizeF / bmp.getHeight();
- float scale = Math.min(widthScale, heightScale);
- int height = (int) (bmp.getHeight() * scale);
- int width = (int) (bmp.getWidth() * scale);
- return Bitmap.createScaledBitmap(bmp, width, height, true);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
deleted file mode 100644
index 228ea9c..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Copyright (C) 2018, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-/** @hide */
-parcelable MediaParceledListSlice;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java b/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
deleted file mode 100644
index ec3fdb7..0000000
--- a/packages/MediaComponents/apex/java/android/media/MediaParceledListSlice.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media;
-
-import android.annotation.UnsupportedAppUsage;
-import android.os.Binder;
-import android.os.Build;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Transfer a large list of objects across an IPC. Splits into multiple transactions if needed.
- * Note: Only use classes declared final in order to avoid subclasses overriding reading/writing
- * parcel logic.
- *
- * TODO: Add test for sending large data
- * @hide
- */
-public class MediaParceledListSlice<T extends Parcelable> implements Parcelable {
- private static final String TAG = "MediaParceledListSlice";
- private static final boolean DEBUG = false;
-
- private static final int MAX_IPC_SIZE = 64 * 1024; // IBinder.MAX_IPC_SIZE
-
- final List<T> mList;
-
- public MediaParceledListSlice(List<T> list) {
- if (list == null) {
- throw new IllegalArgumentException("list shouldn't be null");
- }
- mList = list;
- }
-
- MediaParceledListSlice(Parcel p) {
- final int itemCount = p.readInt();
- mList = new ArrayList<>(itemCount);
- if (DEBUG) {
- Log.d(TAG, "Retrieving " + itemCount + " items");
- }
- if (itemCount <= 0) {
- return;
- }
-
- int i = 0;
- while (i < itemCount) {
- if (p.readInt() == 0) {
- break;
- }
-
- final T parcelable = p.readParcelable(null);
- mList.add(parcelable);
-
- if (DEBUG) {
- Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size() - 1));
- }
- i++;
- }
- if (i >= itemCount) {
- return;
- }
- final IBinder retriever = p.readStrongBinder();
- while (i < itemCount) {
- if (DEBUG) {
- Log.d(TAG, "Reading more @" + i + " of " + itemCount + ": retriever=" + retriever);
- }
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInt(i);
- try {
- retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure retrieving array; only received " + i + " of " + itemCount, e);
- return;
- }
- while (i < itemCount && reply.readInt() != 0) {
- final T parcelable = reply.readParcelable(null);
- mList.add(parcelable);
-
- if (DEBUG) {
- Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size() - 1));
- }
- i++;
- }
- reply.recycle();
- data.recycle();
- }
- }
-
- public List<T> getList() {
- return mList;
- }
-
- /**
- * Write this to another Parcel. Note that this discards the internal Parcel
- * and should not be used anymore. This is so we can pass this to a Binder
- * where we won't have a chance to call recycle on this.
- */
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- final int itemCount = mList.size();
- dest.writeInt(itemCount);
- if (DEBUG) {
- Log.d(TAG, "Writing " + itemCount + " items");
- }
- if (itemCount > 0) {
- int i = 0;
- while (i < itemCount && dest.dataSize() < MAX_IPC_SIZE) {
- dest.writeInt(1);
-
- final T parcelable = mList.get(i);
- dest.writeParcelable(parcelable, flags);
-
- if (DEBUG) {
- Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
- }
- i++;
- }
- if (i < itemCount) {
- dest.writeInt(0);
- Binder retriever = new Binder() {
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code != FIRST_CALL_TRANSACTION) {
- return super.onTransact(code, data, reply, flags);
- }
- int i = data.readInt();
- if (DEBUG) {
- Log.d(TAG, "Writing more @" + i + " of " + itemCount);
- }
- while (i < itemCount && reply.dataSize() < MAX_IPC_SIZE) {
- reply.writeInt(1);
-
- final T parcelable = mList.get(i);
- reply.writeParcelable(parcelable, flags);
-
- if (DEBUG) {
- Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
- }
- i++;
- }
- if (i < itemCount) {
- if (DEBUG) {
- Log.d(TAG, "Breaking @" + i + " of " + itemCount);
- }
- reply.writeInt(0);
- }
- return true;
- }
- };
- if (DEBUG) {
- Log.d(TAG, "Breaking @" + i + " of " + itemCount + ": retriever=" + retriever);
- }
- dest.writeStrongBinder(retriever);
- }
- }
- }
-
- @Override
- public int describeContents() {
- int contents = 0;
- final List<T> list = getList();
- for (int i = 0; i < list.size(); i++) {
- contents |= list.get(i).describeContents();
- }
- return contents;
- }
-
- public static final Parcelable.Creator<MediaParceledListSlice> CREATOR =
- new Parcelable.Creator<MediaParceledListSlice>() {
- @Override
- public MediaParceledListSlice createFromParcel(Parcel in) {
- return new MediaParceledListSlice(in);
- }
-
- @Override
- public MediaParceledListSlice[] newArray(int size) {
- return new MediaParceledListSlice[size];
- }
- };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.aidl b/packages/MediaComponents/apex/java/android/media/Rating.aidl
deleted file mode 100644
index 1dc336a..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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 Rating;
diff --git a/packages/MediaComponents/apex/java/android/media/Rating.java b/packages/MediaComponents/apex/java/android/media/Rating.java
deleted file mode 100644
index 04d5364..0000000
--- a/packages/MediaComponents/apex/java/android/media/Rating.java
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * Copyright (C) 2013 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;
-
-import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A class to encapsulate rating information used as content metadata.
- * A rating is defined by its rating style (see {@link #RATING_HEART},
- * {@link #RATING_THUMB_UP_DOWN}, {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS} or {@link #RATING_PERCENTAGE}) and the actual rating value (which may
- * be defined as "unrated"), both of which are defined when the rating instance is constructed
- * through one of the factory methods.
- */
-public final class Rating implements Parcelable {
- private final static String TAG = "Rating";
-
- /**
- * @hide
- */
- @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
- RATING_5_STARS, RATING_PERCENTAGE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Style {}
-
- /**
- * @hide
- */
- @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
- @Retention(RetentionPolicy.SOURCE)
- public @interface StarStyle {}
-
- /**
- * Indicates a rating style is not supported. A Rating will never have this
- * type, but can be used by other classes to indicate they do not support
- * Rating.
- */
- public final static int RATING_NONE = 0;
-
- /**
- * A rating style with a single degree of rating, "heart" vs "no heart". Can be used to
- * indicate the content referred to is a favorite (or not).
- */
- public final static int RATING_HEART = 1;
-
- /**
- * A rating style for "thumb up" vs "thumb down".
- */
- public final static int RATING_THUMB_UP_DOWN = 2;
-
- /**
- * A rating style with 0 to 3 stars.
- */
- public final static int RATING_3_STARS = 3;
-
- /**
- * A rating style with 0 to 4 stars.
- */
- public final static int RATING_4_STARS = 4;
-
- /**
- * A rating style with 0 to 5 stars.
- */
- public final static int RATING_5_STARS = 5;
-
- /**
- * A rating style expressed as a percentage.
- */
- public final static int RATING_PERCENTAGE = 6;
-
- private final static float RATING_NOT_RATED = -1.0f;
-
- private final int mRatingStyle;
-
- private final float mRatingValue;
-
- private Rating(@Style int ratingStyle, float rating) {
- mRatingStyle = ratingStyle;
- mRatingValue = rating;
- }
-
- @Override
- public String toString() {
- return "Rating:style=" + mRatingStyle + " rating="
- + (mRatingValue < 0.0f ? "unrated" : String.valueOf(mRatingValue));
- }
-
- @Override
- public int describeContents() {
- return mRatingStyle;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRatingStyle);
- dest.writeFloat(mRatingValue);
- }
-
- public static final Parcelable.Creator<Rating> CREATOR
- = new Parcelable.Creator<Rating>() {
- /**
- * Rebuilds a Rating previously stored with writeToParcel().
- * @param p Parcel object to read the Rating from
- * @return a new Rating created from the data in the parcel
- */
- @Override
- public Rating createFromParcel(Parcel p) {
- return new Rating(p.readInt(), p.readFloat());
- }
-
- @Override
- public Rating[] newArray(int size) {
- return new Rating[size];
- }
- };
-
- /**
- * Return a Rating instance with no rating.
- * Create and return a new Rating instance with no rating known for the given
- * rating style.
- * @param ratingStyle one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- * @return null if an invalid rating style is passed, a new Rating instance otherwise.
- */
- public static Rating newUnratedRating(@Style int ratingStyle) {
- switch(ratingStyle) {
- case RATING_HEART:
- case RATING_THUMB_UP_DOWN:
- case RATING_3_STARS:
- case RATING_4_STARS:
- case RATING_5_STARS:
- case RATING_PERCENTAGE:
- return new Rating(ratingStyle, RATING_NOT_RATED);
- default:
- return null;
- }
- }
-
- /**
- * Return a Rating instance with a heart-based rating.
- * Create and return a new Rating instance with a rating style of {@link #RATING_HEART},
- * and a heart-based rating.
- * @param hasHeart true for a "heart selected" rating, false for "heart unselected".
- * @return a new Rating instance.
- */
- public static Rating newHeartRating(boolean hasHeart) {
- return new Rating(RATING_HEART, hasHeart ? 1.0f : 0.0f);
- }
-
- /**
- * Return a Rating instance with a thumb-based rating.
- * Create and return a new Rating instance with a {@link #RATING_THUMB_UP_DOWN}
- * rating style, and a "thumb up" or "thumb down" rating.
- * @param thumbIsUp true for a "thumb up" rating, false for "thumb down".
- * @return a new Rating instance.
- */
- public static Rating newThumbRating(boolean thumbIsUp) {
- return new Rating(RATING_THUMB_UP_DOWN, thumbIsUp ? 1.0f : 0.0f);
- }
-
- /**
- * Return a Rating instance with a star-based rating.
- * Create and return a new Rating instance with one of the star-base rating styles
- * and the given integer or fractional number of stars. Non integer values can for instance
- * be used to represent an average rating value, which might not be an integer number of stars.
- * @param starRatingStyle one of {@link #RATING_3_STARS}, {@link #RATING_4_STARS},
- * {@link #RATING_5_STARS}.
- * @param starRating a number ranging from 0.0f to 3.0f, 4.0f or 5.0f according to
- * the rating style.
- * @return null if the rating style is invalid, or the rating is out of range,
- * a new Rating instance otherwise.
- */
- public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
- float maxRating = -1.0f;
- switch(starRatingStyle) {
- case RATING_3_STARS:
- maxRating = 3.0f;
- break;
- case RATING_4_STARS:
- maxRating = 4.0f;
- break;
- case RATING_5_STARS:
- maxRating = 5.0f;
- break;
- default:
- Log.e(TAG, "Invalid rating style (" + starRatingStyle + ") for a star rating");
- return null;
- }
- if ((starRating < 0.0f) || (starRating > maxRating)) {
- Log.e(TAG, "Trying to set out of range star-based rating");
- return null;
- }
- return new Rating(starRatingStyle, starRating);
- }
-
- /**
- * Return a Rating instance with a percentage-based rating.
- * Create and return a new Rating instance with a {@link #RATING_PERCENTAGE}
- * rating style, and a rating of the given percentage.
- * @param percent the value of the rating
- * @return null if the rating is out of range, a new Rating instance otherwise.
- */
- public static Rating newPercentageRating(float percent) {
- if ((percent < 0.0f) || (percent > 100.0f)) {
- Log.e(TAG, "Invalid percentage-based rating value");
- return null;
- } else {
- return new Rating(RATING_PERCENTAGE, percent);
- }
- }
-
- /**
- * Return whether there is a rating value available.
- * @return true if the instance was not created with {@link #newUnratedRating(int)}.
- */
- public boolean isRated() {
- return mRatingValue >= 0.0f;
- }
-
- /**
- * Return the rating style.
- * @return one of {@link #RATING_HEART}, {@link #RATING_THUMB_UP_DOWN},
- * {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
- * or {@link #RATING_PERCENTAGE}.
- */
- @Style
- public int getRatingStyle() {
- return mRatingStyle;
- }
-
- /**
- * Return whether the rating is "heart selected".
- * @return true if the rating is "heart selected", false if the rating is "heart unselected",
- * if the rating style is not {@link #RATING_HEART} or if it is unrated.
- */
- public boolean hasHeart() {
- if (mRatingStyle != RATING_HEART) {
- return false;
- } else {
- return (mRatingValue == 1.0f);
- }
- }
-
- /**
- * Return whether the rating is "thumb up".
- * @return true if the rating is "thumb up", false if the rating is "thumb down",
- * if the rating style is not {@link #RATING_THUMB_UP_DOWN} or if it is unrated.
- */
- public boolean isThumbUp() {
- if (mRatingStyle != RATING_THUMB_UP_DOWN) {
- return false;
- } else {
- return (mRatingValue == 1.0f);
- }
- }
-
- /**
- * Return the star-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not star-based, or if it is unrated.
- */
- public float getStarRating() {
- switch (mRatingStyle) {
- case RATING_3_STARS:
- case RATING_4_STARS:
- case RATING_5_STARS:
- if (isRated()) {
- return mRatingValue;
- }
- default:
- return -1.0f;
- }
- }
-
- /**
- * Return the percentage-based rating value.
- * @return a rating value greater or equal to 0.0f, or a negative value if the rating style is
- * not percentage-based, or if it is unrated.
- */
- public float getPercentRating() {
- if ((mRatingStyle != RATING_PERCENTAGE) || !isRated()) {
- return -1.0f;
- } else {
- return mRatingValue;
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java b/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
deleted file mode 100644
index 1c017c5..0000000
--- a/packages/MediaComponents/apex/java/android/media/VolumeProvider.java
+++ /dev/null
@@ -1,161 +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;
-
-import android.annotation.IntDef;
-import android.media.session.MediaSession;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Handles requests to adjust or set the volume on a session. This is also used
- * to push volume updates back to the session. The provider must call
- * {@link #setCurrentVolume(int)} each time the volume being provided changes.
- * <p>
- * You can set a volume provider on a session by calling
- * {@link MediaSession#setPlaybackToRemote}.
- */
-public abstract class VolumeProvider {
-
- /**
- * @hide
- */
- @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface ControlType {}
-
- /**
- * The volume is fixed and can not be modified. Requests to change volume
- * should be ignored.
- */
- public static final int VOLUME_CONTROL_FIXED = 0;
-
- /**
- * The volume control uses relative adjustment via
- * {@link #onAdjustVolume(int)}. Attempts to set the volume to a specific
- * value should be ignored.
- */
- public static final int VOLUME_CONTROL_RELATIVE = 1;
-
- /**
- * The volume control uses an absolute value. It may be adjusted using
- * {@link #onAdjustVolume(int)} or set directly using
- * {@link #onSetVolumeTo(int)}.
- */
- public static final int VOLUME_CONTROL_ABSOLUTE = 2;
-
- private final int mControlType;
- private final int mMaxVolume;
- private int mCurrentVolume;
- private Callback mCallback;
-
- /**
- * Create a new volume provider for handling volume events. You must specify
- * the type of volume control, the maximum volume that can be used, and the
- * current volume on the output.
- *
- * @param volumeControl The method for controlling volume that is used by
- * this provider.
- * @param maxVolume The maximum allowed volume.
- * @param currentVolume The current volume on the output.
- */
- public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
- mControlType = volumeControl;
- mMaxVolume = maxVolume;
- mCurrentVolume = currentVolume;
- }
-
- /**
- * Get the volume control type that this volume provider uses.
- *
- * @return The volume control type for this volume provider
- */
- @ControlType
- public final int getVolumeControl() {
- return mControlType;
- }
-
- /**
- * Get the maximum volume this provider allows.
- *
- * @return The max allowed volume.
- */
- public final int getMaxVolume() {
- return mMaxVolume;
- }
-
- /**
- * Gets the current volume. This will be the last value set by
- * {@link #setCurrentVolume(int)}.
- *
- * @return The current volume.
- */
- public final int getCurrentVolume() {
- return mCurrentVolume;
- }
-
- /**
- * Notify the system that the current volume has been changed. This must be
- * called every time the volume changes to ensure it is displayed properly.
- *
- * @param currentVolume The current volume on the output.
- */
- public final void setCurrentVolume(int currentVolume) {
- mCurrentVolume = currentVolume;
- if (mCallback != null) {
- mCallback.onVolumeChanged(this);
- }
- }
-
- /**
- * Override to handle requests to set the volume of the current output.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param volume The volume to set the output to.
- */
- public void onSetVolumeTo(int volume) {
- }
-
- /**
- * Override to handle requests to adjust the volume of the current output.
- * Direction will be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, {@link AudioManager#ADJUST_SAME}.
- * After the volume has been modified {@link #setCurrentVolume} must be
- * called to notify the system.
- *
- * @param direction The direction to change the volume in.
- */
- public void onAdjustVolume(int direction) {
- }
-
- /**
- * Sets a callback to receive volume changes.
- * @hide
- */
- public void setCallback(Callback callback) {
- mCallback = callback;
- }
-
- /**
- * Listens for changes to the volume.
- * @hide
- */
- public static abstract class Callback {
- public abstract void onVolumeChanged(VolumeProvider volumeProvider);
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
deleted file mode 100644
index 782e094..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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.browse;
-
-parcelable MediaBrowser.MediaItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
deleted file mode 100644
index b1b14c6..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowser.java
+++ /dev/null
@@ -1,1171 +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.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.media.MediaDescription;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaController;
-import android.media.session.MediaSession;
-import android.os.Binder;
-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.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.service.media.MediaBrowserService;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map.Entry;
-
-/**
- * Browses media content offered by a link MediaBrowserService.
- * <p>
- * This object is not thread-safe. All calls should happen on the thread on which the browser
- * was constructed.
- * </p>
- * <h3>Standard Extra Data</h3>
- *
- * <p>These are the current standard fields that can be used as extra data via
- * {@link #subscribe(String, Bundle, SubscriptionCallback)},
- * {@link #unsubscribe(String, SubscriptionCallback)}, and
- * {@link SubscriptionCallback#onChildrenLoaded(String, List, Bundle)}.
- *
- * <ul>
- * <li> {@link #EXTRA_PAGE}
- * <li> {@link #EXTRA_PAGE_SIZE}
- * </ul>
- */
-public final class MediaBrowser {
- private static final String TAG = "MediaBrowser";
- private static final boolean DBG = false;
-
- /**
- * Used as an int extra field to denote the page number to subscribe.
- * The value of {@code EXTRA_PAGE} should be greater than or equal to 0.
- *
- * @see #EXTRA_PAGE_SIZE
- */
- public static final String EXTRA_PAGE = "android.media.browse.extra.PAGE";
-
- /**
- * Used as an int extra field to denote the number of media items in a page.
- * The value of {@code EXTRA_PAGE_SIZE} should be greater than or equal to 1.
- *
- * @see #EXTRA_PAGE
- */
- public static final String EXTRA_PAGE_SIZE = "android.media.browse.extra.PAGE_SIZE";
-
- private static final int CONNECT_STATE_DISCONNECTING = 0;
- private static final int CONNECT_STATE_DISCONNECTED = 1;
- private static final int CONNECT_STATE_CONNECTING = 2;
- private static final int CONNECT_STATE_CONNECTED = 3;
- private static final int CONNECT_STATE_SUSPENDED = 4;
-
- private final Context mContext;
- private final ComponentName mServiceComponent;
- private final ConnectionCallback mCallback;
- private final Bundle mRootHints;
- private final Handler mHandler = new Handler();
- private final ArrayMap<String, Subscription> mSubscriptions = new ArrayMap<>();
-
- private volatile int mState = CONNECT_STATE_DISCONNECTED;
- private volatile String mRootId;
- private volatile MediaSession.Token mMediaSessionToken;
- private volatile Bundle mExtras;
-
- private MediaServiceConnection mServiceConnection;
- private IMediaBrowserService mServiceBinder;
- private IMediaBrowserServiceCallbacks mServiceCallbacks;
-
- /**
- * Creates a media browser for the specified media browser service.
- *
- * @param context The context.
- * @param serviceComponent The component name of the media browser service.
- * @param callback The connection callback.
- * @param rootHints An optional bundle of service-specific arguments to send
- * to the media browser service when connecting and retrieving the root id
- * for browsing, or null if none. The contents of this bundle may affect
- * the information returned when browsing.
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_RECENT
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
- * @see android.service.media.MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
- */
- public MediaBrowser(Context context, ComponentName serviceComponent,
- ConnectionCallback callback, Bundle rootHints) {
- if (context == null) {
- throw new IllegalArgumentException("context must not be null");
- }
- if (serviceComponent == null) {
- throw new IllegalArgumentException("service component must not be null");
- }
- if (callback == null) {
- throw new IllegalArgumentException("connection callback must not be null");
- }
- mContext = context;
- mServiceComponent = serviceComponent;
- mCallback = callback;
- mRootHints = rootHints == null ? null : new Bundle(rootHints);
- }
-
- /**
- * Connects to the media browser service.
- * <p>
- * The connection callback specified in the constructor will be invoked
- * when the connection completes or fails.
- * </p>
- */
- public void connect() {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- throw new IllegalStateException("connect() called while neither disconnecting nor "
- + "disconnected (state=" + getStateLabel(mState) + ")");
- }
-
- mState = CONNECT_STATE_CONNECTING;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- if (mState == CONNECT_STATE_DISCONNECTING) {
- return;
- }
- mState = CONNECT_STATE_CONNECTING;
- // TODO: remove this extra check.
- if (DBG) {
- if (mServiceConnection != null) {
- throw new RuntimeException("mServiceConnection should be null. Instead it"
- + " is " + mServiceConnection);
- }
- }
- if (mServiceBinder != null) {
- throw new RuntimeException("mServiceBinder should be null. Instead it is "
- + mServiceBinder);
- }
- if (mServiceCallbacks != null) {
- throw new RuntimeException("mServiceCallbacks should be null. Instead it is "
- + mServiceCallbacks);
- }
-
- final Intent intent = new Intent(MediaBrowserService.SERVICE_INTERFACE);
- intent.setComponent(mServiceComponent);
-
- mServiceConnection = new MediaServiceConnection();
-
- boolean bound = false;
- try {
- bound = mContext.bindService(intent, mServiceConnection,
- Context.BIND_AUTO_CREATE);
- } catch (Exception ex) {
- Log.e(TAG, "Failed binding to service " + mServiceComponent);
- }
-
- if (!bound) {
- // Tell them that it didn't work.
- forceCloseConnection();
- mCallback.onConnectionFailed();
- }
-
- if (DBG) {
- Log.d(TAG, "connect...");
- dump();
- }
- }
- });
- }
-
- /**
- * Disconnects from the media browser service.
- * After this, no more callbacks will be received.
- */
- public void disconnect() {
- // It's ok to call this any state, because allowing this lets apps not have
- // to check isConnected() unnecessarily. They won't appreciate the extra
- // assertions for this. We do everything we can here to go back to a sane state.
- mState = CONNECT_STATE_DISCONNECTING;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // connect() could be called before this. Then we will disconnect and reconnect.
- if (mServiceCallbacks != null) {
- try {
- mServiceBinder.disconnect(mServiceCallbacks);
- } catch (RemoteException ex) {
- // We are disconnecting anyway. Log, just for posterity but it's not
- // a big problem.
- Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
- }
- }
- int state = mState;
- forceCloseConnection();
- // If the state was not CONNECT_STATE_DISCONNECTING, keep the state so that
- // the operation came after disconnect() can be handled properly.
- if (state != CONNECT_STATE_DISCONNECTING) {
- mState = state;
- }
- if (DBG) {
- Log.d(TAG, "disconnect...");
- dump();
- }
- }
- });
- }
-
- /**
- * Null out the variables and unbind from the service. This doesn't include
- * calling disconnect on the service, because we only try to do that in the
- * clean shutdown cases.
- * <p>
- * Everywhere that calls this EXCEPT for disconnect() should follow it with
- * a call to mCallback.onConnectionFailed(). Disconnect doesn't do that callback
- * for a clean shutdown, but everywhere else is a dirty shutdown and should
- * notify the app.
- * <p>
- * Also, mState should be updated properly. Mostly it should be CONNECT_STATE_DIACONNECTED
- * except for disconnect().
- */
- private void forceCloseConnection() {
- if (mServiceConnection != null) {
- try {
- mContext.unbindService(mServiceConnection);
- } catch (IllegalArgumentException e) {
- if (DBG) {
- Log.d(TAG, "unbindService failed", e);
- }
- }
- }
- mState = CONNECT_STATE_DISCONNECTED;
- mServiceConnection = null;
- mServiceBinder = null;
- mServiceCallbacks = null;
- mRootId = null;
- mMediaSessionToken = null;
- }
-
- /**
- * Returns whether the browser is connected to the service.
- */
- public boolean isConnected() {
- return mState == CONNECT_STATE_CONNECTED;
- }
-
- /**
- * Gets the service component that the media browser is connected to.
- */
- public @NonNull ComponentName getServiceComponent() {
- if (!isConnected()) {
- throw new IllegalStateException("getServiceComponent() called while not connected" +
- " (state=" + mState + ")");
- }
- return mServiceComponent;
- }
-
- /**
- * Gets the root id.
- * <p>
- * Note that the root id may become invalid or change when the
- * browser is disconnected.
- * </p>
- *
- * @throws IllegalStateException if not connected.
- */
- public @NonNull String getRoot() {
- if (!isConnected()) {
- throw new IllegalStateException("getRoot() called while not connected (state="
- + getStateLabel(mState) + ")");
- }
- return mRootId;
- }
-
- /**
- * Gets any extras for the media service.
- *
- * @throws IllegalStateException if not connected.
- */
- public @Nullable Bundle getExtras() {
- if (!isConnected()) {
- throw new IllegalStateException("getExtras() called while not connected (state="
- + getStateLabel(mState) + ")");
- }
- return mExtras;
- }
-
- /**
- * Gets the media session token associated with the media browser.
- * <p>
- * Note that the session token may become invalid or change when the
- * browser is disconnected.
- * </p>
- *
- * @return The session token for the browser, never null.
- *
- * @throws IllegalStateException if not connected.
- */
- public @NonNull MediaSession.Token getSessionToken() {
- if (!isConnected()) {
- throw new IllegalStateException("getSessionToken() called while not connected (state="
- + mState + ")");
- }
- return mMediaSessionToken;
- }
-
- /**
- * Queries for information about the media items that are contained within
- * the specified id and subscribes to receive updates when they change.
- * <p>
- * The list of subscriptions is maintained even when not connected and is
- * restored after the reconnection. It is ok to subscribe while not connected
- * but the results will not be returned until the connection completes.
- * </p>
- * <p>
- * If the id is already subscribed with a different callback then the new
- * callback will replace the previous one and the child data will be
- * reloaded.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be subscribed.
- * @param callback The callback to receive the list of children.
- */
- public void subscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
- subscribeInternal(parentId, null, callback);
- }
-
- /**
- * Queries with service-specific arguments for information about the media items
- * that are contained within the specified id and subscribes to receive updates
- * when they change.
- * <p>
- * The list of subscriptions is maintained even when not connected and is
- * restored after the reconnection. It is ok to subscribe while not connected
- * but the results will not be returned until the connection completes.
- * </p>
- * <p>
- * If the id is already subscribed with a different callback then the new
- * callback will replace the previous one and the child data will be
- * reloaded.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be subscribed.
- * @param options The bundle of service-specific arguments to send to the media
- * browser service. The contents of this bundle may affect the
- * information returned when browsing.
- * @param callback The callback to receive the list of children.
- */
- public void subscribe(@NonNull String parentId, @NonNull Bundle options,
- @NonNull SubscriptionCallback callback) {
- if (options == null) {
- throw new IllegalArgumentException("options cannot be null");
- }
- subscribeInternal(parentId, new Bundle(options), callback);
- }
-
- /**
- * Unsubscribes for changes to the children of the specified media id.
- * <p>
- * The query callback will no longer be invoked for results associated with
- * this id once this method returns.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be unsubscribed.
- */
- public void unsubscribe(@NonNull String parentId) {
- unsubscribeInternal(parentId, null);
- }
-
- /**
- * Unsubscribes for changes to the children of the specified media id through a callback.
- * <p>
- * The query callback will no longer be invoked for results associated with
- * this id once this method returns.
- * </p>
- *
- * @param parentId The id of the parent media item whose list of children
- * will be unsubscribed.
- * @param callback A callback sent to the media browser service to subscribe.
- */
- public void unsubscribe(@NonNull String parentId, @NonNull SubscriptionCallback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- unsubscribeInternal(parentId, callback);
- }
-
- /**
- * Retrieves a specific {@link MediaItem} from the connected service. Not
- * all services may support this, so falling back to subscribing to the
- * parent's id should be used when unavailable.
- *
- * @param mediaId The id of the item to retrieve.
- * @param cb The callback to receive the result on.
- */
- public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
- if (TextUtils.isEmpty(mediaId)) {
- throw new IllegalArgumentException("mediaId cannot be empty.");
- }
- if (cb == null) {
- throw new IllegalArgumentException("cb cannot be null.");
- }
- if (mState != CONNECT_STATE_CONNECTED) {
- Log.i(TAG, "Not connected, unable to retrieve the MediaItem.");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- cb.onError(mediaId);
- }
- });
- return;
- }
- ResultReceiver receiver = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- if (!isConnected()) {
- return;
- }
- if (resultCode != 0 || resultData == null
- || !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError(mediaId);
- return;
- }
- Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
- if (item != null && !(item instanceof MediaItem)) {
- cb.onError(mediaId);
- return;
- }
- cb.onItemLoaded((MediaItem)item);
- }
- };
- try {
- mServiceBinder.getMediaItem(mediaId, receiver, mServiceCallbacks);
- } catch (RemoteException e) {
- Log.i(TAG, "Remote error getting media item.");
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- cb.onError(mediaId);
- }
- });
- }
- }
-
- private void subscribeInternal(String parentId, Bundle options, SubscriptionCallback callback) {
- // Check arguments.
- if (TextUtils.isEmpty(parentId)) {
- throw new IllegalArgumentException("parentId cannot be empty.");
- }
- if (callback == null) {
- throw new IllegalArgumentException("callback cannot be null");
- }
- // Update or create the subscription.
- Subscription sub = mSubscriptions.get(parentId);
- if (sub == null) {
- sub = new Subscription();
- mSubscriptions.put(parentId, sub);
- }
- sub.putCallback(mContext, options, callback);
-
- // If we are connected, tell the service that we are watching. If we aren't connected,
- // the service will be told when we connect.
- if (isConnected()) {
- try {
- if (options == null) {
- mServiceBinder.addSubscriptionDeprecated(parentId, mServiceCallbacks);
- }
- mServiceBinder.addSubscription(parentId, callback.mToken, options,
- mServiceCallbacks);
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "addSubscription failed with RemoteException parentId=" + parentId);
- }
- }
- }
-
- private void unsubscribeInternal(String parentId, SubscriptionCallback callback) {
- // Check arguments.
- if (TextUtils.isEmpty(parentId)) {
- throw new IllegalArgumentException("parentId cannot be empty.");
- }
-
- Subscription sub = mSubscriptions.get(parentId);
- if (sub == null) {
- return;
- }
- // Tell the service if necessary.
- try {
- if (callback == null) {
- if (isConnected()) {
- mServiceBinder.removeSubscriptionDeprecated(parentId, mServiceCallbacks);
- mServiceBinder.removeSubscription(parentId, null, mServiceCallbacks);
- }
- } else {
- final List<SubscriptionCallback> callbacks = sub.getCallbacks();
- final List<Bundle> optionsList = sub.getOptionsList();
- for (int i = callbacks.size() - 1; i >= 0; --i) {
- if (callbacks.get(i) == callback) {
- if (isConnected()) {
- mServiceBinder.removeSubscription(
- parentId, callback.mToken, mServiceCallbacks);
- }
- callbacks.remove(i);
- optionsList.remove(i);
- }
- }
- }
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "removeSubscription failed with RemoteException parentId=" + parentId);
- }
-
- if (sub.isEmpty() || callback == null) {
- mSubscriptions.remove(parentId);
- }
- }
-
- /**
- * For debugging.
- */
- private static String getStateLabel(int state) {
- switch (state) {
- case CONNECT_STATE_DISCONNECTING:
- return "CONNECT_STATE_DISCONNECTING";
- case CONNECT_STATE_DISCONNECTED:
- return "CONNECT_STATE_DISCONNECTED";
- case CONNECT_STATE_CONNECTING:
- return "CONNECT_STATE_CONNECTING";
- case CONNECT_STATE_CONNECTED:
- return "CONNECT_STATE_CONNECTED";
- case CONNECT_STATE_SUSPENDED:
- return "CONNECT_STATE_SUSPENDED";
- default:
- return "UNKNOWN/" + state;
- }
- }
-
- private final void onServiceConnected(final IMediaBrowserServiceCallbacks callback,
- final String root, final MediaSession.Token session, final Bundle extra) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Check to make sure there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onConnect")) {
- return;
- }
- // Don't allow them to call us twice.
- if (mState != CONNECT_STATE_CONNECTING) {
- Log.w(TAG, "onConnect from service while mState="
- + getStateLabel(mState) + "... ignoring");
- return;
- }
- mRootId = root;
- mMediaSessionToken = session;
- mExtras = extra;
- mState = CONNECT_STATE_CONNECTED;
-
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- mCallback.onConnected();
-
- // we may receive some subscriptions before we are connected, so re-subscribe
- // everything now
- for (Entry<String, Subscription> subscriptionEntry : mSubscriptions.entrySet()) {
- String id = subscriptionEntry.getKey();
- Subscription sub = subscriptionEntry.getValue();
- List<SubscriptionCallback> callbackList = sub.getCallbacks();
- List<Bundle> optionsList = sub.getOptionsList();
- for (int i = 0; i < callbackList.size(); ++i) {
- try {
- mServiceBinder.addSubscription(id, callbackList.get(i).mToken,
- optionsList.get(i), mServiceCallbacks);
- } catch (RemoteException ex) {
- // Process is crashing. We will disconnect, and upon reconnect we will
- // automatically reregister. So nothing to do here.
- Log.d(TAG, "addSubscription failed with RemoteException parentId="
- + id);
- }
- }
- }
- }
- });
- }
-
- private final void onConnectionFailed(final IMediaBrowserServiceCallbacks callback) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Log.e(TAG, "onConnectFailed for " + mServiceComponent);
-
- // Check to make sure there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onConnectFailed")) {
- return;
- }
- // Don't allow them to call us twice.
- if (mState != CONNECT_STATE_CONNECTING) {
- Log.w(TAG, "onConnect from service while mState="
- + getStateLabel(mState) + "... ignoring");
- return;
- }
-
- // Clean up
- forceCloseConnection();
-
- // Tell the app.
- mCallback.onConnectionFailed();
- }
- });
- }
-
- private final void onLoadChildren(final IMediaBrowserServiceCallbacks callback,
- final String parentId, final MediaParceledListSlice list, final Bundle options) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- // Check that there hasn't been a disconnect or a different
- // ServiceConnection.
- if (!isCurrent(callback, "onLoadChildren")) {
- return;
- }
-
- if (DBG) {
- Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
- }
-
- // Check that the subscription is still subscribed.
- final Subscription subscription = mSubscriptions.get(parentId);
- if (subscription != null) {
- // Tell the app.
- SubscriptionCallback subscriptionCallback =
- subscription.getCallback(mContext, options);
- if (subscriptionCallback != null) {
- List<MediaItem> data = list == null ? null : list.getList();
- if (options == null) {
- if (data == null) {
- subscriptionCallback.onError(parentId);
- } else {
- subscriptionCallback.onChildrenLoaded(parentId, data);
- }
- } else {
- if (data == null) {
- subscriptionCallback.onError(parentId, options);
- } else {
- subscriptionCallback.onChildrenLoaded(parentId, data, options);
- }
- }
- return;
- }
- }
- if (DBG) {
- Log.d(TAG, "onLoadChildren for id that isn't subscribed id=" + parentId);
- }
- }
- });
- }
-
- /**
- * Return true if {@code callback} is the current ServiceCallbacks. Also logs if it's not.
- */
- private boolean isCurrent(IMediaBrowserServiceCallbacks callback, String funcName) {
- if (mServiceCallbacks != callback || mState == CONNECT_STATE_DISCONNECTING
- || mState == CONNECT_STATE_DISCONNECTED) {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
- + mServiceCallbacks + " this=" + this);
- }
- return false;
- }
- return true;
- }
-
- private ServiceCallbacks getNewServiceCallbacks() {
- return new ServiceCallbacks(this);
- }
-
- /**
- * Log internal state.
- * @hide
- */
- void dump() {
- Log.d(TAG, "MediaBrowser...");
- Log.d(TAG, " mServiceComponent=" + mServiceComponent);
- Log.d(TAG, " mCallback=" + mCallback);
- Log.d(TAG, " mRootHints=" + mRootHints);
- Log.d(TAG, " mState=" + getStateLabel(mState));
- Log.d(TAG, " mServiceConnection=" + mServiceConnection);
- Log.d(TAG, " mServiceBinder=" + mServiceBinder);
- Log.d(TAG, " mServiceCallbacks=" + mServiceCallbacks);
- Log.d(TAG, " mRootId=" + mRootId);
- Log.d(TAG, " mMediaSessionToken=" + mMediaSessionToken);
- }
-
- /**
- * A class with information on a single media item for use in browsing/searching media.
- * MediaItems are application dependent so we cannot guarantee that they contain the
- * right values.
- */
- 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 { }
-
- /**
- * 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 id of this item may be passed to
- * {@link MediaController.TransportControls#playFromMediaId(String, Bundle)}
- * to start playing it.
- * </p>
- */
- public static final int FLAG_PLAYABLE = 1 << 1;
-
- /**
- * Create a new MediaItem for use in browsing media.
- * @param description The description of the media, which must include a
- * media id.
- * @param flags The flags for this item.
- */
- public MediaItem(@NonNull MediaDescription description, @Flags int flags) {
- 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;
- }
-
- /**
- * Private constructor.
- */
- 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];
- }
- };
-
- /**
- * 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;
- }
-
- /**
- * Returns the description of the media.
- */
- public @NonNull MediaDescription getDescription() {
- return mDescription;
- }
-
- /**
- * Returns the media id in the {@link MediaDescription} for this item.
- * @see android.media.MediaMetadata#METADATA_KEY_MEDIA_ID
- */
- public @Nullable String getMediaId() {
- return mDescription.getMediaId();
- }
- }
-
- /**
- * Callbacks for connection related events.
- */
- public static class ConnectionCallback {
- /**
- * Invoked after {@link MediaBrowser#connect()} when the request has successfully completed.
- */
- public void onConnected() {
- }
-
- /**
- * Invoked when the client is disconnected from the media browser.
- */
- public void onConnectionSuspended() {
- }
-
- /**
- * Invoked when the connection to the media browser failed.
- */
- public void onConnectionFailed() {
- }
- }
-
- /**
- * Callbacks for subscription related events.
- */
- public static abstract class SubscriptionCallback {
- Binder mToken;
-
- public SubscriptionCallback() {
- mToken = new Binder();
- }
-
- /**
- * Called when the list of children is loaded or updated.
- *
- * @param parentId The media id of the parent media item.
- * @param children The children which were loaded.
- */
- public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
- }
-
- /**
- * Called when the list of children is loaded or updated.
- *
- * @param parentId The media id of the parent media item.
- * @param children The children which were loaded.
- * @param options The bundle of service-specific arguments sent to the media
- * browser service. The contents of this bundle may affect the
- * information returned when browsing.
- */
- public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
- @NonNull Bundle options) {
- }
-
- /**
- * Called when the id 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>
- *
- * @param parentId The media id of the parent media item whose children could
- * not be loaded.
- */
- public void onError(@NonNull String parentId) {
- }
-
- /**
- * Called when the id 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>
- *
- * @param parentId The media id of the parent media item whose children could
- * not be loaded.
- * @param options The bundle of service-specific arguments sent to the media
- * browser service.
- */
- public void onError(@NonNull String parentId, @NonNull Bundle options) {
- }
- }
-
- /**
- * Callback for receiving the result of {@link #getItem}.
- */
- public static abstract class ItemCallback {
- /**
- * Called when the item has been returned by the connected service.
- *
- * @param item The item that was returned or null if it doesn't exist.
- */
- public void onItemLoaded(MediaItem item) {
- }
-
- /**
- * Called there was an error retrieving it or the connected service doesn't support
- * {@link #getItem}.
- *
- * @param mediaId The media id of the media item which could not be loaded.
- */
- public void onError(@NonNull String mediaId) {
- }
- }
-
- /**
- * ServiceConnection to the other app.
- */
- private class MediaServiceConnection implements ServiceConnection {
- @Override
- public void onServiceConnected(final ComponentName name, final IBinder binder) {
- postOrRun(new Runnable() {
- @Override
- public void run() {
- if (DBG) {
- Log.d(TAG, "MediaServiceConnection.onServiceConnected name=" + name
- + " binder=" + binder);
- dump();
- }
-
- // Make sure we are still the current connection, and that they haven't called
- // disconnect().
- if (!isCurrent("onServiceConnected")) {
- return;
- }
-
- // Save their binder
- mServiceBinder = IMediaBrowserService.Stub.asInterface(binder);
-
- // We make a new mServiceCallbacks each time we connect so that we can drop
- // responses from previous connections.
- mServiceCallbacks = getNewServiceCallbacks();
- mState = CONNECT_STATE_CONNECTING;
-
- // Call connect, which is async. When we get a response from that we will
- // say that we're connected.
- try {
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- mServiceBinder.connect(mContext.getPackageName(), mRootHints,
- mServiceCallbacks);
- } catch (RemoteException ex) {
- // Connect failed, which isn't good. But the auto-reconnect on the service
- // will take over and we will come back. We will also get the
- // onServiceDisconnected, which has all the cleanup code. So let that do
- // it.
- Log.w(TAG, "RemoteException during connect for " + mServiceComponent);
- if (DBG) {
- Log.d(TAG, "ServiceCallbacks.onConnect...");
- dump();
- }
- }
- }
- });
- }
-
- @Override
- public void onServiceDisconnected(final ComponentName name) {
- postOrRun(new Runnable() {
- @Override
- public void run() {
- if (DBG) {
- Log.d(TAG, "MediaServiceConnection.onServiceDisconnected name=" + name
- + " this=" + this + " mServiceConnection=" + mServiceConnection);
- dump();
- }
-
- // Make sure we are still the current connection, and that they haven't called
- // disconnect().
- if (!isCurrent("onServiceDisconnected")) {
- return;
- }
-
- // Clear out what we set in onServiceConnected
- mServiceBinder = null;
- mServiceCallbacks = null;
-
- // And tell the app that it's suspended.
- mState = CONNECT_STATE_SUSPENDED;
- mCallback.onConnectionSuspended();
- }
- });
- }
-
- private void postOrRun(Runnable r) {
- if (Thread.currentThread() == mHandler.getLooper().getThread()) {
- r.run();
- } else {
- mHandler.post(r);
- }
- }
-
- /**
- * Return true if this is the current ServiceConnection. Also logs if it's not.
- */
- private boolean isCurrent(String funcName) {
- if (mServiceConnection != this || mState == CONNECT_STATE_DISCONNECTING
- || mState == CONNECT_STATE_DISCONNECTED) {
- if (mState != CONNECT_STATE_DISCONNECTING && mState != CONNECT_STATE_DISCONNECTED) {
- // Check mState, because otherwise this log is noisy.
- Log.i(TAG, funcName + " for " + mServiceComponent + " with mServiceConnection="
- + mServiceConnection + " this=" + this);
- }
- return false;
- }
- return true;
- }
- }
-
- /**
- * Callbacks from the service.
- */
- private static class ServiceCallbacks extends IMediaBrowserServiceCallbacks.Stub {
- private WeakReference<MediaBrowser> mMediaBrowser;
-
- public ServiceCallbacks(MediaBrowser mediaBrowser) {
- mMediaBrowser = new WeakReference<MediaBrowser>(mediaBrowser);
- }
-
- /**
- * The other side has acknowledged our connection. The parameters to this function
- * are the initial data as requested.
- */
- @Override
- public void onConnect(String root, MediaSession.Token session,
- final Bundle extras) {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onServiceConnected(this, root, session, extras);
- }
- }
-
- /**
- * The other side does not like us. Tell the app via onConnectionFailed.
- */
- @Override
- public void onConnectFailed() {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onConnectionFailed(this);
- }
- }
-
- @Override
- public void onLoadChildren(String parentId, MediaParceledListSlice list) {
- onLoadChildrenWithOptions(parentId, list, null);
- }
-
- @Override
- public void onLoadChildrenWithOptions(String parentId, MediaParceledListSlice list,
- final Bundle options) {
- MediaBrowser mediaBrowser = mMediaBrowser.get();
- if (mediaBrowser != null) {
- mediaBrowser.onLoadChildren(this, parentId, list, options);
- }
- }
- }
-
- private static class Subscription {
- private final List<SubscriptionCallback> mCallbacks;
- private final List<Bundle> mOptionsList;
-
- public Subscription() {
- mCallbacks = new ArrayList<>();
- mOptionsList = new ArrayList<>();
- }
-
- public boolean isEmpty() {
- return mCallbacks.isEmpty();
- }
-
- public List<Bundle> getOptionsList() {
- return mOptionsList;
- }
-
- public List<SubscriptionCallback> getCallbacks() {
- return mCallbacks;
- }
-
- public SubscriptionCallback getCallback(Context context, Bundle options) {
- if (options != null) {
- options.setClassLoader(context.getClassLoader());
- }
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- return mCallbacks.get(i);
- }
- }
- return null;
- }
-
- public void putCallback(Context context, Bundle options, SubscriptionCallback callback) {
- if (options != null) {
- options.setClassLoader(context.getClassLoader());
- }
- for (int i = 0; i < mOptionsList.size(); ++i) {
- if (MediaBrowserUtils.areSameOptions(mOptionsList.get(i), options)) {
- mCallbacks.set(i, callback);
- return;
- }
- }
- mCallbacks.add(callback);
- mOptionsList.add(options);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java b/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
deleted file mode 100644
index 2943e60..0000000
--- a/packages/MediaComponents/apex/java/android/media/browse/MediaBrowserUtils.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2016 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.os.Bundle;
-
-/**
- * @hide
- */
-public class MediaBrowserUtils {
- public static boolean areSameOptions(Bundle options1, Bundle options2) {
- if (options1 == options2) {
- return true;
- } else if (options1 == null) {
- return options2.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
- && options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
- } else if (options2 == null) {
- return options1.getInt(MediaBrowser.EXTRA_PAGE, -1) == -1
- && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1) == -1;
- } else {
- return options1.getInt(MediaBrowser.EXTRA_PAGE, -1)
- == options2.getInt(MediaBrowser.EXTRA_PAGE, -1)
- && options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1)
- == options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- }
- }
-
- public static boolean hasDuplicatedItems(Bundle options1, Bundle options2) {
- int page1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int page2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int pageSize1 = options1 == null ? -1 : options1.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- int pageSize2 = options2 == null ? -1 : options2.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
-
- int startIndex1, startIndex2, endIndex1, endIndex2;
- if (page1 == -1 || pageSize1 == -1) {
- startIndex1 = 0;
- endIndex1 = Integer.MAX_VALUE;
- } else {
- startIndex1 = pageSize1 * page1;
- endIndex1 = startIndex1 + pageSize1 - 1;
- }
-
- if (page2 == -1 || pageSize2 == -1) {
- startIndex2 = 0;
- endIndex2 = Integer.MAX_VALUE;
- } else {
- startIndex2 = pageSize2 * page2;
- endIndex2 = startIndex2 + pageSize2 - 1;
- }
-
- if (startIndex1 <= startIndex2 && startIndex2 <= endIndex1) {
- return true;
- } else if (startIndex1 <= endIndex2 && endIndex2 <= endIndex1) {
- return true;
- }
- return false;
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
deleted file mode 100644
index 4b9e4bd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IActiveSessionsListener.aidl
+++ /dev/null
@@ -1,26 +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.session;
-
-import android.media.session.MediaSession;
-
-/**
- * Listens for changes to the list of active sessions.
- * @hide
- */
-oneway interface IActiveSessionsListener {
- void onActiveSessionsChanged(in List<MediaSession.Token> sessions);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
deleted file mode 100644
index 322bffa..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ICallback.aidl
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.media.session.MediaSession;
-import android.view.KeyEvent;
-
-/**
- * @hide
- */
-oneway interface ICallback {
- void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
- in MediaSession.Token sessionToken);
- void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
- in ComponentName mediaButtonReceiver);
-
- void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
- void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
deleted file mode 100644
index aa98ea3..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnMediaKeyListener.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-/**
- * Listener to handle media key.
- * @hide
- */
-oneway interface IOnMediaKeyListener {
- void onMediaKey(in KeyEvent event, in ResultReceiver result);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl b/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
deleted file mode 100644
index 07b8347..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/IOnVolumeKeyLongPressListener.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (C) 2016 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.session;
-
-import android.view.KeyEvent;
-
-/**
- * Listener to handle volume key long-press.
- * @hide
- */
-oneway interface IOnVolumeKeyLongPressListener {
- void onVolumeKeyLongPress(in KeyEvent event);
-}
-
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl b/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
deleted file mode 100644
index 14b1c64..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISession.aidl
+++ /dev/null
@@ -1,54 +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.session;
-
-import android.app.PendingIntent;
-//import android.media.AudioAttributes;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ISessionController;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Interface to a MediaSession in the system.
- * @hide
- */
-interface ISession {
- void sendEvent(String event, in Bundle data);
- ISessionController getController();
- void setFlags(int flags);
- void setActive(boolean active);
- void setMediaButtonReceiver(in PendingIntent mbr);
- void setLaunchPendingIntent(in PendingIntent pi);
- void destroy();
-
- // These commands are for the TransportPerformer
- void setMetadata(in MediaMetadata metadata, long duration, String metadataDescription);
- void setPlaybackState(in PlaybackState state);
- void setQueue(in MediaParceledListSlice queue);
- void setQueueTitle(CharSequence title);
- void setExtras(in Bundle extras);
- void setRatingType(int type);
-
- // These commands relate to volume handling
- //TODO(b/119751592): Decide if AudioAttributes should be updated.
- //void setPlaybackToLocal(in AudioAttributes attributes);
- void setPlaybackToRemote(int control, int max);
- void setCurrentVolume(int currentVolume);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
deleted file mode 100644
index 626338d..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionCallback.aidl
+++ /dev/null
@@ -1,71 +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.session;
-
-import android.content.Intent;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * @hide
- */
-oneway interface ISessionCallback {
- void onCommand(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String command, in Bundle args, in ResultReceiver cb);
- void onMediaButton(String packageName, int pid, int uid, in Intent mediaButtonIntent,
- int sequenceNumber, in ResultReceiver cb);
- void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, in Intent mediaButtonIntent);
-
- // These callbacks are for the TransportPerformer
- void onPrepare(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId, in Bundle extras);
- void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query, in Bundle extras);
- void onPrepareFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void onPlay(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPlayFromMediaId(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void onPlayFromSearch(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String query, in Bundle extras);
- void onPlayFromUri(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void onSkipToTrack(String packageName, int pid, int uid, ISessionControllerCallback caller,
- long id);
- void onPause(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onStop(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onNext(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onPrevious(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onFastForward(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onRewind(String packageName, int pid, int uid, ISessionControllerCallback caller);
- void onSeekTo(String packageName, int pid, int uid, ISessionControllerCallback caller,
- long pos);
- void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
- in Rating rating);
- void onCustomAction(String packageName, int pid, int uid, ISessionControllerCallback caller,
- String action, in Bundle args);
-
- // These callbacks are for volume handling
- void onAdjustVolume(String packageName, int pid, int uid, ISessionControllerCallback caller,
- int direction);
- void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
deleted file mode 100644
index 433b12f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionController.aidl
+++ /dev/null
@@ -1,88 +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.session;
-
-import android.app.PendingIntent;
-import android.content.Intent;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.session.ISessionControllerCallback;
-import android.media.session.MediaSession;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-import android.view.KeyEvent;
-
-import java.util.List;
-
-/**
- * Interface to MediaSessionRecord in the system.
- * @hide
- */
-interface ISessionController {
- void sendCommand(String packageName, ISessionControllerCallback caller,
- String command, in Bundle args, in ResultReceiver cb);
- boolean sendMediaButton(String packageName, ISessionControllerCallback caller,
- boolean asSystemService, in KeyEvent mediaButton);
- void registerCallbackListener(String packageName, ISessionControllerCallback cb);
- void unregisterCallbackListener(ISessionControllerCallback cb);
- boolean isTransportControlEnabled();
- String getPackageName();
- String getTag();
- PendingIntent getLaunchPendingIntent();
- long getFlags();
- ParcelableVolumeInfo getVolumeAttributes();
- void adjustVolume(String packageName, String opPackageName, ISessionControllerCallback caller,
- boolean asSystemService, int direction, int flags);
- void setVolumeTo(String packageName, String opPackageName, ISessionControllerCallback caller,
- int value, int flags);
-
- // These commands are for the TransportControls
- void prepare(String packageName, ISessionControllerCallback caller);
- void prepareFromMediaId(String packageName, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void prepareFromSearch(String packageName, ISessionControllerCallback caller,
- String string, in Bundle extras);
- void prepareFromUri(String packageName, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void play(String packageName, ISessionControllerCallback caller);
- void playFromMediaId(String packageName, ISessionControllerCallback caller,
- String mediaId, in Bundle extras);
- void playFromSearch(String packageName, ISessionControllerCallback caller,
- String string, in Bundle extras);
- void playFromUri(String packageName, ISessionControllerCallback caller,
- in Uri uri, in Bundle extras);
- void skipToQueueItem(String packageName, ISessionControllerCallback caller, long id);
- void pause(String packageName, ISessionControllerCallback caller);
- void stop(String packageName, ISessionControllerCallback caller);
- void next(String packageName, ISessionControllerCallback caller);
- void previous(String packageName, ISessionControllerCallback caller);
- void fastForward(String packageName, ISessionControllerCallback caller);
- void rewind(String packageName, ISessionControllerCallback caller);
- void seekTo(String packageName, ISessionControllerCallback caller, long pos);
- void rate(String packageName, ISessionControllerCallback caller, in Rating rating);
- void sendCustomAction(String packageName, ISessionControllerCallback caller,
- String action, in Bundle args);
- MediaMetadata getMetadata();
- PlaybackState getPlaybackState();
- MediaParceledListSlice getQueue();
- CharSequence getQueueTitle();
- Bundle getExtras();
- int getRatingType();
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
deleted file mode 100644
index f5cc4f6..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionControllerCallback.aidl
+++ /dev/null
@@ -1,39 +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.session;
-
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.session.ParcelableVolumeInfo;
-import android.media.session.PlaybackState;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-oneway interface ISessionControllerCallback {
- void onEvent(String event, in Bundle extras);
- void onSessionDestroyed();
-
- // These callbacks are for the TransportController
- void onPlaybackStateChanged(in PlaybackState state);
- void onMetadataChanged(in MediaMetadata metadata);
- void onQueueChanged(in MediaParceledListSlice queue);
- void onQueueTitleChanged(CharSequence title);
- void onExtrasChanged(in Bundle extras);
- void onVolumeInfoChanged(in ParcelableVolumeInfo info);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl b/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
deleted file mode 100644
index d6c226f..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ISessionManager.aidl
+++ /dev/null
@@ -1,58 +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.session;
-
-import android.content.ComponentName;
-import android.media.IRemoteVolumeController;
-import android.media.session.IActiveSessionsListener;
-import android.media.session.ICallback;
-import android.media.session.IOnMediaKeyListener;
-import android.media.session.IOnVolumeKeyLongPressListener;
-import android.media.session.ISession;
-import android.media.session.ISessionCallback;
-import android.os.Bundle;
-import android.view.KeyEvent;
-
-/**
- * Interface to the MediaSessionManagerService
- * @hide
- */
-interface ISessionManager {
- ISession createSession(String packageName, in ISessionCallback cb, String tag, int userId);
- List<IBinder> getSessions(in ComponentName compName, int userId);
- void dispatchMediaKeyEvent(String packageName, boolean asSystemService, in KeyEvent keyEvent,
- boolean needWakeLock);
- void dispatchVolumeKeyEvent(String packageName, String opPackageName, boolean asSystemService,
- in KeyEvent keyEvent, int stream, boolean musicOnly);
- void dispatchAdjustVolume(String packageName, String opPackageName, int suggestedStream,
- int delta, int flags);
- void addSessionsListener(in IActiveSessionsListener listener, in ComponentName compName,
- int userId);
- void removeSessionsListener(in IActiveSessionsListener listener);
-
- // This is for the system volume UI only
- void setRemoteVolumeController(in IRemoteVolumeController rvc);
-
- // For PhoneWindowManager to precheck media keys
- boolean isGlobalPriorityActive();
-
- void setCallback(in ICallback callback);
- void setOnVolumeKeyLongPressListener(in IOnVolumeKeyLongPressListener listener);
- void setOnMediaKeyListener(in IOnMediaKeyListener listener);
-
- // MediaSession2
- boolean isTrusted(String controllerPackageName, int controllerPid, int controllerUid);
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaController.java b/packages/MediaComponents/apex/java/android/media/session/MediaController.java
deleted file mode 100644
index 65682a8..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaController.java
+++ /dev/null
@@ -1,1190 +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.session;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.media.AudioAttributes;
-import android.media.AudioManager;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.KeyEvent;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Allows an app to interact with an ongoing media session. Media buttons and
- * other commands can be sent to the session. A callback may be registered to
- * receive updates from the session, such as metadata and play state changes.
- * <p>
- * A MediaController can be created through {@link MediaSessionManager} if you
- * hold the "android.permission.MEDIA_CONTENT_CONTROL" permission or are an
- * enabled notification listener or by getting a {@link MediaSession.Token}
- * directly from the session owner.
- * <p>
- * MediaController objects are thread-safe.
- */
-public final class MediaController {
- private static final String TAG = "MediaController";
-
- private static final int MSG_EVENT = 1;
- private static final int MSG_UPDATE_PLAYBACK_STATE = 2;
- private static final int MSG_UPDATE_METADATA = 3;
- private static final int MSG_UPDATE_VOLUME = 4;
- private static final int MSG_UPDATE_QUEUE = 5;
- private static final int MSG_UPDATE_QUEUE_TITLE = 6;
- private static final int MSG_UPDATE_EXTRAS = 7;
- private static final int MSG_DESTROYED = 8;
-
- private final ISessionController mSessionBinder;
-
- private final MediaSession.Token mToken;
- private final Context mContext;
- private final CallbackStub mCbStub = new CallbackStub(this);
- private final ArrayList<MessageHandler> mCallbacks = new ArrayList<MessageHandler>();
- private final Object mLock = new Object();
-
- private boolean mCbRegistered = false;
- private String mPackageName;
- private String mTag;
-
- private final TransportControls mTransportControls;
-
- /**
- * Call for creating a MediaController directly from a binder. Should only
- * be used by framework code.
- *
- * @hide
- */
- public MediaController(Context context, ISessionController sessionBinder) {
- if (sessionBinder == null) {
- throw new IllegalArgumentException("Session token cannot be null");
- }
- if (context == null) {
- throw new IllegalArgumentException("Context cannot be null");
- }
- mSessionBinder = sessionBinder;
- mTransportControls = new TransportControls();
- mToken = new MediaSession.Token(sessionBinder);
- mContext = context;
- }
-
- /**
- * Create a new MediaController from a session's token.
- *
- * @param context The caller's context.
- * @param token The token for the session.
- */
- public MediaController(@NonNull Context context, @NonNull MediaSession.Token token) {
- this(context, token.getBinder());
- }
-
- /**
- * Get a {@link TransportControls} instance to send transport actions to
- * the associated session.
- *
- * @return A transport controls instance.
- */
- public @NonNull TransportControls getTransportControls() {
- return mTransportControls;
- }
-
- /**
- * Send the specified media button event to the session. Only media keys can
- * be sent by this method, other keys will be ignored.
- *
- * @param keyEvent The media button event to dispatch.
- * @return true if the event was sent to the session, false otherwise.
- */
- public boolean dispatchMediaButtonEvent(@NonNull KeyEvent keyEvent) {
- return dispatchMediaButtonEventInternal(false, keyEvent);
- }
-
- /**
- * Dispatches the media button event as system service to the session.
- * <p>
- * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
- * foreground activity didn't consume the key from the hardware devices.
- *
- * @param keyEvent media key event
- * @return {@code true} if the event was sent to the session, {@code false} otherwise
- * @hide
- */
- public boolean dispatchMediaButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
- return dispatchMediaButtonEventInternal(true, keyEvent);
- }
-
- private boolean dispatchMediaButtonEventInternal(boolean asSystemService,
- @NonNull KeyEvent keyEvent) {
- if (keyEvent == null) {
- throw new IllegalArgumentException("KeyEvent may not be null");
- }
- if (!KeyEvent.isMediaSessionKey(keyEvent.getKeyCode())) {
- return false;
- }
- try {
- return mSessionBinder.sendMediaButton(mContext.getPackageName(), mCbStub,
- asSystemService, keyEvent);
- } catch (RemoteException e) {
- // System is dead. =(
- }
- return false;
- }
-
- /**
- * Dispatches the volume button event as system service to the session.
- * <p>
- * Should be only called by the {@link com.android.internal.policy.PhoneWindow} when the
- * foreground activity didn't consume the key from the hardware devices.
- *
- * @param keyEvent volume key event
- * @hide
- */
- public void dispatchVolumeButtonEventAsSystemService(@NonNull KeyEvent keyEvent) {
- switch (keyEvent.getAction()) {
- case KeyEvent.ACTION_DOWN: {
- int direction = 0;
- switch (keyEvent.getKeyCode()) {
- case KeyEvent.KEYCODE_VOLUME_UP:
- direction = AudioManager.ADJUST_RAISE;
- break;
- case KeyEvent.KEYCODE_VOLUME_DOWN:
- direction = AudioManager.ADJUST_LOWER;
- break;
- case KeyEvent.KEYCODE_VOLUME_MUTE:
- direction = AudioManager.ADJUST_TOGGLE_MUTE;
- break;
- }
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(),
- mContext.getOpPackageName(), mCbStub, true, direction,
- AudioManager.FLAG_SHOW_UI);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy", e);
- }
- }
-
- case KeyEvent.ACTION_UP: {
- final int flags = AudioManager.FLAG_PLAY_SOUND | AudioManager.FLAG_VIBRATE
- | AudioManager.FLAG_FROM_KEY;
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(),
- mContext.getOpPackageName(), mCbStub, true, 0, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy", e);
- }
- }
- }
- }
-
- /**
- * Get the current playback state for this session.
- *
- * @return The current PlaybackState or null
- */
- public @Nullable PlaybackState getPlaybackState() {
- try {
- return mSessionBinder.getPlaybackState();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPlaybackState.", e);
- return null;
- }
- }
-
- /**
- * Get the current metadata for this session.
- *
- * @return The current MediaMetadata or null.
- */
- public @Nullable MediaMetadata getMetadata() {
- try {
- return mSessionBinder.getMetadata();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getMetadata.", e);
- return null;
- }
- }
-
- /**
- * Get the current play queue for this session if one is set. If you only
- * care about the current item {@link #getMetadata()} should be used.
- *
- * @return The current play queue or null.
- */
- public @Nullable List<MediaSession.QueueItem> getQueue() {
- try {
- MediaParceledListSlice queue = mSessionBinder.getQueue();
- if (queue != null) {
- return queue.getList();
- }
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getQueue.", e);
- }
- return null;
- }
-
- /**
- * Get the queue title for this session.
- */
- public @Nullable CharSequence getQueueTitle() {
- try {
- return mSessionBinder.getQueueTitle();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getQueueTitle", e);
- }
- return null;
- }
-
- /**
- * Get the extras for this session.
- */
- public @Nullable Bundle getExtras() {
- try {
- return mSessionBinder.getExtras();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getExtras", e);
- }
- return null;
- }
-
- /**
- * Get the rating type supported by the session. One of:
- * <ul>
- * <li>{@link Rating#RATING_NONE}</li>
- * <li>{@link Rating#RATING_HEART}</li>
- * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
- * <li>{@link Rating#RATING_3_STARS}</li>
- * <li>{@link Rating#RATING_4_STARS}</li>
- * <li>{@link Rating#RATING_5_STARS}</li>
- * <li>{@link Rating#RATING_PERCENTAGE}</li>
- * </ul>
- *
- * @return The supported rating type
- */
- public int getRatingType() {
- try {
- return mSessionBinder.getRatingType();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getRatingType.", e);
- return Rating.RATING_NONE;
- }
- }
-
- /**
- * Get the flags for this session. Flags are defined in {@link MediaSession}.
- *
- * @return The current set of flags for the session.
- */
- public @MediaSession.SessionFlags long getFlags() {
- try {
- return mSessionBinder.getFlags();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getFlags.", e);
- }
- return 0;
- }
-
- /**
- * Get the current playback info for this session.
- *
- * @return The current playback info or null.
- */
- public @Nullable PlaybackInfo getPlaybackInfo() {
- try {
- ParcelableVolumeInfo result = mSessionBinder.getVolumeAttributes();
- return new PlaybackInfo(result.volumeType, result.audioAttrs, result.controlType,
- result.maxVolume, result.currentVolume);
-
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getAudioInfo.", e);
- }
- return null;
- }
-
- /**
- * Get an intent for launching UI associated with this session if one
- * exists.
- *
- * @return A {@link PendingIntent} to launch UI or null.
- */
- public @Nullable PendingIntent getSessionActivity() {
- try {
- return mSessionBinder.getLaunchPendingIntent();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling getPendingIntent.", e);
- }
- return null;
- }
-
- /**
- * Get the token for the session this is connected to.
- *
- * @return The token for the connected session.
- */
- public @NonNull MediaSession.Token getSessionToken() {
- return mToken;
- }
-
- /**
- * Set the volume of the output this session is playing on. The command will
- * be ignored if it does not support
- * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
- * {@link AudioManager} may be used to affect the handling.
- *
- * @see #getPlaybackInfo()
- * @param value The value to set it to, between 0 and the reported max.
- * @param flags Flags from {@link AudioManager} to include with the volume
- * request.
- */
- public void setVolumeTo(int value, int flags) {
- try {
- mSessionBinder.setVolumeTo(mContext.getPackageName(), mContext.getOpPackageName(),
- mCbStub, value, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling setVolumeTo.", e);
- }
- }
-
- /**
- * Adjust the volume of the output this session is playing on. The direction
- * must be one of {@link AudioManager#ADJUST_LOWER},
- * {@link AudioManager#ADJUST_RAISE}, or {@link AudioManager#ADJUST_SAME}.
- * The command will be ignored if the session does not support
- * {@link VolumeProvider#VOLUME_CONTROL_RELATIVE} or
- * {@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}. The flags in
- * {@link AudioManager} may be used to affect the handling.
- *
- * @see #getPlaybackInfo()
- * @param direction The direction to adjust the volume in.
- * @param flags Any flags to pass with the command.
- */
- public void adjustVolume(int direction, int flags) {
- try {
- mSessionBinder.adjustVolume(mContext.getPackageName(), mContext.getOpPackageName(),
- mCbStub, false, direction, flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling adjustVolumeBy.", e);
- }
- }
-
- /**
- * Registers a callback to receive updates from the Session. Updates will be
- * posted on the caller's thread.
- *
- * @param callback The callback object, must not be null.
- */
- public void registerCallback(@NonNull Callback callback) {
- registerCallback(callback, null);
- }
-
- /**
- * Registers a callback to receive updates from the session. Updates will be
- * posted on the specified handler's thread.
- *
- * @param callback The callback object, must not be null.
- * @param handler The handler to post updates on. If null the callers thread
- * will be used.
- */
- public void registerCallback(@NonNull Callback callback, @Nullable Handler handler) {
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
- if (handler == null) {
- handler = new Handler();
- }
- synchronized (mLock) {
- addCallbackLocked(callback, handler);
- }
- }
-
- /**
- * Unregisters the specified callback. If an update has already been posted
- * you may still receive it after calling this method.
- *
- * @param callback The callback to remove.
- */
- public void unregisterCallback(@NonNull Callback callback) {
- if (callback == null) {
- throw new IllegalArgumentException("callback must not be null");
- }
- synchronized (mLock) {
- removeCallbackLocked(callback);
- }
- }
-
- /**
- * Sends a generic command to the session. It is up to the session creator
- * to decide what commands and parameters they will support. As such,
- * commands should only be sent to sessions that the controller owns.
- *
- * @param command The command to send
- * @param args Any parameters to include with the command
- * @param cb The callback to receive the result on
- */
- public void sendCommand(@NonNull String command, @Nullable Bundle args,
- @Nullable ResultReceiver cb) {
- if (TextUtils.isEmpty(command)) {
- throw new IllegalArgumentException("command cannot be null or empty");
- }
- try {
- mSessionBinder.sendCommand(mContext.getPackageName(), mCbStub, command, args, cb);
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCommand.", e);
- }
- }
-
- /**
- * Get the session owner's package name.
- *
- * @return The package name of of the session owner.
- */
- public String getPackageName() {
- if (mPackageName == null) {
- try {
- mPackageName = mSessionBinder.getPackageName();
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in getPackageName.", e);
- }
- }
- return mPackageName;
- }
-
- /**
- * Get the session's tag for debugging purposes.
- *
- * @return The session's tag.
- * @hide
- */
- public String getTag() {
- if (mTag == null) {
- try {
- mTag = mSessionBinder.getTag();
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in getTag.", e);
- }
- }
- return mTag;
- }
-
- /*
- * @hide
- */
- ISessionController getSessionBinder() {
- return mSessionBinder;
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public boolean controlsSameSession(MediaController other) {
- if (other == null) return false;
- return mSessionBinder.asBinder() == other.getSessionBinder().asBinder();
- }
-
- private void addCallbackLocked(Callback cb, Handler handler) {
- if (getHandlerForCallbackLocked(cb) != null) {
- Log.w(TAG, "Callback is already added, ignoring");
- return;
- }
- MessageHandler holder = new MessageHandler(handler.getLooper(), cb);
- mCallbacks.add(holder);
- holder.mRegistered = true;
-
- if (!mCbRegistered) {
- try {
- mSessionBinder.registerCallbackListener(mContext.getPackageName(), mCbStub);
- mCbRegistered = true;
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in registerCallback", e);
- }
- }
- }
-
- private boolean removeCallbackLocked(Callback cb) {
- boolean success = false;
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- MessageHandler handler = mCallbacks.get(i);
- if (cb == handler.mCallback) {
- mCallbacks.remove(i);
- success = true;
- handler.mRegistered = false;
- }
- }
- if (mCbRegistered && mCallbacks.size() == 0) {
- try {
- mSessionBinder.unregisterCallbackListener(mCbStub);
- } catch (RemoteException e) {
- Log.e(TAG, "Dead object in removeCallbackLocked");
- }
- mCbRegistered = false;
- }
- return success;
- }
-
- private MessageHandler getHandlerForCallbackLocked(Callback cb) {
- if (cb == null) {
- throw new IllegalArgumentException("Callback cannot be null");
- }
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- MessageHandler handler = mCallbacks.get(i);
- if (cb == handler.mCallback) {
- return handler;
- }
- }
- return null;
- }
-
- private final void postMessage(int what, Object obj, Bundle data) {
- synchronized (mLock) {
- for (int i = mCallbacks.size() - 1; i >= 0; i--) {
- mCallbacks.get(i).post(what, obj, data);
- }
- }
- }
-
- /**
- * Callback for receiving updates from the session. A Callback can be
- * registered using {@link #registerCallback}.
- */
- public static abstract class Callback {
- /**
- * Override to handle the session being destroyed. The session is no
- * longer valid after this call and calls to it will be ignored.
- */
- public void onSessionDestroyed() {
- }
-
- /**
- * Override to handle custom events sent by the session owner without a
- * specified interface. Controllers should only handle these for
- * sessions they own.
- *
- * @param event The event from the session.
- * @param extras Optional parameters for the event, may be null.
- */
- public void onSessionEvent(@NonNull String event, @Nullable Bundle extras) {
- }
-
- /**
- * Override to handle changes in playback state.
- *
- * @param state The new playback state of the session
- */
- public void onPlaybackStateChanged(@Nullable PlaybackState state) {
- }
-
- /**
- * Override to handle changes to the current metadata.
- *
- * @param metadata The current metadata for the session or null if none.
- * @see MediaMetadata
- */
- public void onMetadataChanged(@Nullable MediaMetadata metadata) {
- }
-
- /**
- * Override to handle changes to items in the queue.
- *
- * @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.QueueItem
- */
- public void onQueueChanged(@Nullable List<MediaSession.QueueItem> queue) {
- }
-
- /**
- * Override to handle changes to the queue title.
- *
- * @param title The title that should be displayed along with the play queue such as
- * "Now Playing". May be null if there is no such title.
- */
- public void onQueueTitleChanged(@Nullable CharSequence title) {
- }
-
- /**
- * Override to handle changes to the {@link MediaSession} extras.
- *
- * @param extras The extras that can include other information associated with the
- * {@link MediaSession}.
- */
- public void onExtrasChanged(@Nullable Bundle extras) {
- }
-
- /**
- * Override to handle changes to the audio info.
- *
- * @param info The current audio info for this session.
- */
- public void onAudioInfoChanged(PlaybackInfo info) {
- }
- }
-
- /**
- * Interface for controlling media playback on a session. This allows an app
- * to send media transport commands to the session.
- */
- public final class TransportControls {
- private static final String TAG = "TransportController";
-
- private TransportControls() {
- }
-
- /**
- * Request that the player prepare its playback. In other words, other sessions can continue
- * to play during the preparation of this session. This method can be used to speed up the
- * start of the playback. Once the preparation is done, the session will change its playback
- * state to {@link PlaybackState#STATE_PAUSED}. Afterwards, {@link #play} can be called to
- * start playback.
- */
- public void prepare() {
- try {
- mSessionBinder.prepare(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare.", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific media id. In other words, other
- * sessions can continue to play during the preparation of this session. This method can be
- * used to speed up the start of the playback. Once the preparation is done, the session
- * will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromMediaId} can be directly called without this method.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromMediaId(String mediaId, Bundle extras) {
- if (TextUtils.isEmpty(mediaId)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty String for prepareFromMediaId.");
- }
- try {
- mSessionBinder.prepareFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + mediaId + ").", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific search query. An empty or null
- * query should be treated as a request to prepare any music. In other words, other sessions
- * can continue to play during the preparation of this session. This method can be used to
- * speed up the start of the playback. Once the preparation is done, the session will
- * change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromSearch} can be directly called without this method.
- *
- * @param query The search query.
- * @param extras Optional extras that can include extra information
- * about the query.
- */
- public void prepareFromSearch(String query, Bundle extras) {
- if (query == null) {
- // This is to remain compatible with
- // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- query = "";
- }
- try {
- mSessionBinder.prepareFromSearch(mContext.getPackageName(), mCbStub, query,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + query + ").", e);
- }
- }
-
- /**
- * Request that the player prepare playback for a specific {@link Uri}. In other words,
- * other sessions can continue to play during the preparation of this session. This method
- * can be used to speed up the start of the playback. Once the preparation is done, the
- * session will change its playback state to {@link PlaybackState#STATE_PAUSED}. Afterwards,
- * {@link #play} can be called to start playback. If the preparation is not needed,
- * {@link #playFromUri} can be directly called without this method.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be prepared.
- */
- public void prepareFromUri(Uri uri, Bundle extras) {
- if (uri == null || Uri.EMPTY.equals(uri)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty Uri for prepareFromUri.");
- }
- try {
- mSessionBinder.prepareFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling prepare(" + uri + ").", e);
- }
- }
-
- /**
- * Request that the player start its playback at its current position.
- */
- public void play() {
- try {
- mSessionBinder.play(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play.", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific media id.
- *
- * @param mediaId The id of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- 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.playFromMediaId(mContext.getPackageName(), mCbStub, mediaId,
- extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + mediaId + ").", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific search query.
- * An empty or null query should be treated as a request to play any
- * music.
- *
- * @param query The search query.
- * @param extras Optional extras that can include extra information
- * about the query.
- */
- public void playFromSearch(String query, Bundle extras) {
- if (query == null) {
- // This is to remain compatible with
- // INTENT_ACTION_MEDIA_PLAY_FROM_SEARCH
- query = "";
- }
- try {
- mSessionBinder.playFromSearch(mContext.getPackageName(), mCbStub, query, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + query + ").", e);
- }
- }
-
- /**
- * Request that the player start playback for a specific {@link Uri}.
- *
- * @param uri The URI of the requested media.
- * @param extras Optional extras that can include extra information about the media item
- * to be played.
- */
- public void playFromUri(Uri uri, Bundle extras) {
- if (uri == null || Uri.EMPTY.equals(uri)) {
- throw new IllegalArgumentException(
- "You must specify a non-empty Uri for playFromUri.");
- }
- try {
- mSessionBinder.playFromUri(mContext.getPackageName(), mCbStub, uri, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling play(" + uri + ").", e);
- }
- }
-
- /**
- * 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 skipToQueueItem(long id) {
- try {
- mSessionBinder.skipToQueueItem(mContext.getPackageName(), mCbStub, id);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling skipToItem(" + id + ").", e);
- }
- }
-
- /**
- * Request that the player pause its playback and stay at its current
- * position.
- */
- public void pause() {
- try {
- mSessionBinder.pause(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling pause.", e);
- }
- }
-
- /**
- * Request that the player stop its playback; it may clear its state in
- * whatever way is appropriate.
- */
- public void stop() {
- try {
- mSessionBinder.stop(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling stop.", e);
- }
- }
-
- /**
- * Move to a new location in the media stream.
- *
- * @param pos Position to move to, in milliseconds.
- */
- public void seekTo(long pos) {
- try {
- mSessionBinder.seekTo(mContext.getPackageName(), mCbStub, pos);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling seekTo.", e);
- }
- }
-
- /**
- * Start fast forwarding. If playback is already fast forwarding this
- * may increase the rate.
- */
- public void fastForward() {
- try {
- mSessionBinder.fastForward(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling fastForward.", e);
- }
- }
-
- /**
- * Skip to the next item.
- */
- public void skipToNext() {
- try {
- mSessionBinder.next(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling next.", e);
- }
- }
-
- /**
- * Start rewinding. If playback is already rewinding this may increase
- * the rate.
- */
- public void rewind() {
- try {
- mSessionBinder.rewind(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rewind.", e);
- }
- }
-
- /**
- * Skip to the previous item.
- */
- public void skipToPrevious() {
- try {
- mSessionBinder.previous(mContext.getPackageName(), mCbStub);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling previous.", e);
- }
- }
-
- /**
- * Rate the current content. This will cause the rating to be set for
- * the current user. The Rating type must match the type returned by
- * {@link #getRatingType()}.
- *
- * @param rating The rating to set for the current content
- */
- public void setRating(Rating rating) {
- try {
- mSessionBinder.rate(mContext.getPackageName(), mCbStub, rating);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error calling rate.", e);
- }
- }
-
- /**
- * Send a custom action back for the {@link MediaSession} to perform.
- *
- * @param customAction The action to perform.
- * @param args Optional arguments to supply to the {@link MediaSession} for this
- * custom action.
- */
- public void sendCustomAction(@NonNull PlaybackState.CustomAction customAction,
- @Nullable Bundle args) {
- if (customAction == null) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
- }
- sendCustomAction(customAction.getAction(), args);
- }
-
- /**
- * Send the id and args from a custom action back for the {@link MediaSession} to perform.
- *
- * @see #sendCustomAction(PlaybackState.CustomAction action, Bundle args)
- * @param action The action identifier of the {@link PlaybackState.CustomAction} as
- * specified by the {@link MediaSession}.
- * @param args Optional arguments to supply to the {@link MediaSession} for this
- * custom action.
- */
- public void sendCustomAction(@NonNull String action, @Nullable Bundle args) {
- if (TextUtils.isEmpty(action)) {
- throw new IllegalArgumentException("CustomAction cannot be null.");
- }
- try {
- mSessionBinder.sendCustomAction(mContext.getPackageName(), mCbStub, action, args);
- } catch (RemoteException e) {
- Log.d(TAG, "Dead object in sendCustomAction.", e);
- }
- }
- }
-
- /**
- * Holds information about the current playback and how audio is handled for
- * this session.
- */
- public static final class PlaybackInfo {
- /**
- * The session uses remote playback.
- */
- public static final int PLAYBACK_TYPE_REMOTE = 2;
- /**
- * The session uses local playback.
- */
- public static final int PLAYBACK_TYPE_LOCAL = 1;
-
- private final int mVolumeType;
- private final int mVolumeControl;
- private final int mMaxVolume;
- private final int mCurrentVolume;
- private final AudioAttributes mAudioAttrs;
-
- /**
- * @hide
- */
- public PlaybackInfo(int type, AudioAttributes attrs, int control, int max, int current) {
- mVolumeType = type;
- mAudioAttrs = attrs;
- mVolumeControl = control;
- mMaxVolume = max;
- mCurrentVolume = current;
- }
-
- /**
- * Get the type of playback which affects volume handling. One of:
- * <ul>
- * <li>{@link #PLAYBACK_TYPE_LOCAL}</li>
- * <li>{@link #PLAYBACK_TYPE_REMOTE}</li>
- * </ul>
- *
- * @return The type of playback this session is using.
- */
- public int getPlaybackType() {
- return mVolumeType;
- }
-
- /**
- * Get the audio attributes for this session. The attributes will affect
- * volume handling for the session. When the volume type is
- * {@link PlaybackInfo#PLAYBACK_TYPE_REMOTE} these may be ignored by the
- * remote volume handler.
- *
- * @return The attributes for this session.
- */
- public AudioAttributes getAudioAttributes() {
- return mAudioAttrs;
- }
-
- /**
- * Get the type of volume control that can be used. One of:
- * <ul>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_ABSOLUTE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_RELATIVE}</li>
- * <li>{@link VolumeProvider#VOLUME_CONTROL_FIXED}</li>
- * </ul>
- *
- * @return The type of volume control that may be used with this
- * session.
- */
- public int getVolumeControl() {
- return mVolumeControl;
- }
-
- /**
- * Get the maximum volume that may be set for this session.
- *
- * @return The maximum allowed volume where this session is playing.
- */
- public int getMaxVolume() {
- return mMaxVolume;
- }
-
- /**
- * Get the current volume for this session.
- *
- * @return The current volume where this session is playing.
- */
- public int getCurrentVolume() {
- return mCurrentVolume;
- }
- }
-
- private final static class CallbackStub extends ISessionControllerCallback.Stub {
- private final WeakReference<MediaController> mController;
-
- public CallbackStub(MediaController controller) {
- mController = new WeakReference<MediaController>(controller);
- }
-
- @Override
- public void onSessionDestroyed() {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_DESTROYED, null, null);
- }
- }
-
- @Override
- public void onEvent(String event, Bundle extras) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_EVENT, event, extras);
- }
- }
-
- @Override
- public void onPlaybackStateChanged(PlaybackState state) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_PLAYBACK_STATE, state, null);
- }
- }
-
- @Override
- public void onMetadataChanged(MediaMetadata metadata) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_METADATA, metadata, null);
- }
- }
-
- @Override
- public void onQueueChanged(MediaParceledListSlice parceledQueue) {
- List<MediaSession.QueueItem> queue = parceledQueue == null ? null : parceledQueue
- .getList();
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_QUEUE, queue, null);
- }
- }
-
- @Override
- public void onQueueTitleChanged(CharSequence title) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_QUEUE_TITLE, title, null);
- }
- }
-
- @Override
- public void onExtrasChanged(Bundle extras) {
- MediaController controller = mController.get();
- if (controller != null) {
- controller.postMessage(MSG_UPDATE_EXTRAS, extras, null);
- }
- }
-
- @Override
- public void onVolumeInfoChanged(ParcelableVolumeInfo pvi) {
- MediaController controller = mController.get();
- if (controller != null) {
- PlaybackInfo info = new PlaybackInfo(pvi.volumeType, pvi.audioAttrs,
- pvi.controlType, pvi.maxVolume, pvi.currentVolume);
- controller.postMessage(MSG_UPDATE_VOLUME, info, null);
- }
- }
-
- }
-
- private final static class MessageHandler extends Handler {
- private final MediaController.Callback mCallback;
- private boolean mRegistered = false;
-
- public MessageHandler(Looper looper, MediaController.Callback cb) {
- super(looper);
- mCallback = cb;
- }
-
- @Override
- public void handleMessage(Message msg) {
- if (!mRegistered) {
- return;
- }
- switch (msg.what) {
- case MSG_EVENT:
- mCallback.onSessionEvent((String) msg.obj, msg.getData());
- break;
- case MSG_UPDATE_PLAYBACK_STATE:
- mCallback.onPlaybackStateChanged((PlaybackState) msg.obj);
- break;
- case MSG_UPDATE_METADATA:
- mCallback.onMetadataChanged((MediaMetadata) msg.obj);
- break;
- case MSG_UPDATE_QUEUE:
- mCallback.onQueueChanged((List<MediaSession.QueueItem>) msg.obj);
- break;
- case MSG_UPDATE_QUEUE_TITLE:
- mCallback.onQueueTitleChanged((CharSequence) msg.obj);
- break;
- case MSG_UPDATE_EXTRAS:
- mCallback.onExtrasChanged((Bundle) msg.obj);
- break;
- case MSG_UPDATE_VOLUME:
- mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj);
- break;
- case MSG_DESTROYED:
- mCallback.onSessionDestroyed();
- break;
- }
- }
-
- public void post(int what, Object obj, Bundle data) {
- Message msg = obtainMessage(what, obj);
- msg.setAsynchronous(true);
- msg.setData(data);
- msg.sendToTarget();
- }
- }
-
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl b/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
deleted file mode 100644
index f657cef..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/* 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.session;
-
-parcelable MediaSession.Token;
-parcelable MediaSession.QueueItem;
\ No newline at end of file
diff --git a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java b/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
deleted file mode 100644
index 3cbeff9..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/MediaSession.java
+++ /dev/null
@@ -1,1569 +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.session;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.Intent;
-import android.media.AudioAttributes;
-import android.media.MediaDescription;
-import android.media.MediaMetadata;
-import android.media.MediaParceledListSlice;
-import android.media.Rating;
-import android.media.VolumeProvider;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Parcel;
-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.util.Pair;
-import android.view.KeyEvent;
-import android.view.ViewConfiguration;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Allows interaction with media controllers, volume keys, media buttons, and
- * transport controls.
- * <p>
- * A MediaSession should be created when an app wants to publish media playback
- * information or handle media keys. In general an app only needs one session
- * for all playback, though multiple sessions can be created to provide finer
- * grain controls of media.
- * <p>
- * Once a session is created the owner of the session may pass its
- * {@link #getSessionToken() session token} to other processes to allow them to
- * create a {@link MediaController} to interact with the session.
- * <p>
- * To receive commands, media keys, and other events a {@link Callback} must be
- * set with {@link #setCallback(Callback)} and {@link #setActive(boolean)
- * setActive(true)} must be called.
- * <p>
- * When an app is finished performing playback it must call {@link #release()}
- * to clean up the session and notify any controllers.
- * <p>
- * MediaSession objects are thread safe.
- */
-public final class MediaSession {
- private static final String TAG = "MediaSession";
-
- /**
- * Set this flag on the session to indicate that it can handle media button
- * events.
- * @deprecated This flag is no longer used. All media sessions are expected to handle media
- * button events now.
- */
- @Deprecated
- public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1 << 0;
-
- /**
- * Set this flag on the session to indicate that it handles transport
- * control commands through its {@link Callback}.
- * @deprecated This flag is no longer used. All media sessions are expected to handle transport
- * controls now.
- */
- @Deprecated
- public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
-
- /**
- * System only flag for a session that needs to have priority over all other
- * sessions. This flag ensures this session will receive media button events
- * regardless of the current ordering in the system.
- *
- * @hide
- */
- public static final int FLAG_EXCLUSIVE_GLOBAL_PRIORITY = 1 << 16;
-
- /**
- * @hide
- */
- public static final int INVALID_UID = -1;
-
- /**
- * @hide
- */
- public static final int INVALID_PID = -1;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = true, value = {
- FLAG_HANDLES_MEDIA_BUTTONS,
- FLAG_HANDLES_TRANSPORT_CONTROLS,
- FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
- public @interface SessionFlags { }
-
- private final Object mLock = new Object();
- private final int mMaxBitmapSize;
-
- private final MediaSession.Token mSessionToken;
- private final MediaController mController;
- private final ISession mBinder;
- private final CallbackStub mCbStub;
-
- // Do not change the name of mCallback. Support lib accesses this by using reflection.
- @UnsupportedAppUsage
- private CallbackMessageHandler mCallback;
- private VolumeProvider mVolumeProvider;
- private PlaybackState mPlaybackState;
-
- private boolean mActive = false;
-
- /**
- * Creates a new session. The session will automatically be registered with
- * the system but will not be published until {@link #setActive(boolean)
- * setActive(true)} is called. You must call {@link #release()} when
- * finished with the session.
- *
- * @param context The context to use to create the session.
- * @param tag A short name for debugging purposes.
- */
- public MediaSession(@NonNull Context context, @NonNull String tag) {
- this(context, tag, UserHandle.myUserId());
- }
-
- /**
- * Creates a new session as the specified user. To create a session as a
- * user other than your own you must hold the
- * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL}
- * permission.
- *
- * @param context The context to use to create the session.
- * @param tag A short name for debugging purposes.
- * @param userId The user id to create the session as.
- * @hide
- */
- public MediaSession(@NonNull Context context, @NonNull String tag, int userId) {
- if (context == null) {
- throw new IllegalArgumentException("context cannot be null.");
- }
- if (TextUtils.isEmpty(tag)) {
- throw new IllegalArgumentException("tag cannot be null or empty");
- }
- mMaxBitmapSize = context.getResources().getDimensionPixelSize(
- android.R.dimen.config_mediaMetadataBitmapMaxSize);
- mCbStub = new CallbackStub(this);
- MediaSessionManager manager = (MediaSessionManager) context
- .getSystemService(Context.MEDIA_SESSION_SERVICE);
- try {
- //TODO(b/119749862): Resolve hidden API usage. MediaSessioManager#createSession
- //mBinder = manager.createSession(mCbStub, tag, userId);
- mBinder = null; //TODO: remove this.
- mSessionToken = new Token(mBinder.getController());
- mController = new MediaController(context, mSessionToken);
- } catch (RemoteException e) {
- throw new RuntimeException("Remote error creating session.", e);
- }
- }
-
- /**
- * Set the callback to receive updates for the MediaSession. This includes
- * media button events and transport controls. The caller's thread will be
- * used to post updates.
- * <p>
- * Set the callback to null to stop receiving updates.
- *
- * @param callback The callback object
- */
- public void setCallback(@Nullable Callback callback) {
- setCallback(callback, null);
- }
-
- /**
- * Set the callback to receive updates for the MediaSession. This includes
- * media button events and transport controls.
- * <p>
- * Set the callback to null to stop receiving updates.
- *
- * @param callback The callback to receive updates on.
- * @param handler The handler that events should be posted on.
- */
- public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
- synchronized (mLock) {
- if (mCallback != null) {
- // We're updating the callback, clear the session from the old one.
- mCallback.mCallback.mSession = null;
- mCallback.removeCallbacksAndMessages(null);
- }
- if (callback == null) {
- mCallback = null;
- return;
- }
- if (handler == null) {
- handler = new Handler();
- }
- callback.mSession = this;
- CallbackMessageHandler msgHandler = new CallbackMessageHandler(handler.getLooper(),
- callback);
- mCallback = msgHandler;
- }
- }
-
- /**
- * Set an intent for launching UI for this Session. This can be used as a
- * quick link to an ongoing media screen. The intent should be for an
- * activity that may be started using {@link Activity#startActivity(Intent)}.
- *
- * @param pi The intent to launch to show UI for this Session.
- */
- public void setSessionActivity(@Nullable PendingIntent pi) {
- try {
- mBinder.setLaunchPendingIntent(pi);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setLaunchPendingIntent.", e);
- }
- }
-
- /**
- * Set a pending intent for your media button receiver to allow restarting
- * playback after the session has been stopped. If your app is started in
- * this way an {@link Intent#ACTION_MEDIA_BUTTON} intent will be sent via
- * the pending intent.
- *
- * @param mbr The {@link PendingIntent} to send the media button event to.
- */
- public void setMediaButtonReceiver(@Nullable PendingIntent mbr) {
- try {
- mBinder.setMediaButtonReceiver(mbr);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setMediaButtonReceiver.", e);
- }
- }
-
- /**
- * Set any flags for the session.
- *
- * @param flags The flags to set for this session.
- */
- public void setFlags(@SessionFlags int flags) {
- try {
- mBinder.setFlags(flags);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setFlags.", e);
- }
- }
-
- /**
- * Set the attributes for this session's audio. This will affect the
- * system's volume handling for this session. If
- * {@link #setPlaybackToRemote} was previously called it will stop receiving
- * volume commands and the system will begin sending volume changes to the
- * appropriate stream.
- * <p>
- * By default sessions use attributes for media.
- *
- * @param attributes The {@link AudioAttributes} for this session's audio.
- */
- public void setPlaybackToLocal(AudioAttributes attributes) {
- if (attributes == null) {
- throw new IllegalArgumentException("Attributes cannot be null for local playback.");
- }
- //TODO(b/119751592): Decide if AudioAttributes should be updated.
- /*
- try {
- mBinder.setPlaybackToLocal(attributes);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setPlaybackToLocal.", e);
- }
- */
- }
-
- /**
- * Configure this session to use remote volume handling. This must be called
- * to receive volume button events, otherwise the system will adjust the
- * appropriate stream volume for this session. If
- * {@link #setPlaybackToLocal} was previously called the system will stop
- * handling volume changes for this session and pass them to the volume
- * provider instead.
- *
- * @param volumeProvider The provider that will handle volume changes. May
- * not be null.
- */
- public void setPlaybackToRemote(@NonNull VolumeProvider volumeProvider) {
- if (volumeProvider == null) {
- throw new IllegalArgumentException("volumeProvider may not be null!");
- }
- synchronized (mLock) {
- mVolumeProvider = volumeProvider;
- }
- volumeProvider.setCallback(new VolumeProvider.Callback() {
- @Override
- public void onVolumeChanged(VolumeProvider volumeProvider) {
- notifyRemoteVolumeChanged(volumeProvider);
- }
- });
-
- try {
- mBinder.setPlaybackToRemote(volumeProvider.getVolumeControl(),
- volumeProvider.getMaxVolume());
- mBinder.setCurrentVolume(volumeProvider.getCurrentVolume());
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setPlaybackToRemote.", e);
- }
- }
-
- /**
- * Set if this session is currently active and ready to receive commands. If
- * set to false your session's controller may not be discoverable. You must
- * set the session to active before it can start receiving media button
- * events or transport commands.
- *
- * @param active Whether this session is active or not.
- */
- public void setActive(boolean active) {
- if (mActive == active) {
- return;
- }
- try {
- mBinder.setActive(active);
- mActive = active;
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failure in setActive.", e);
- }
- }
-
- /**
- * Get the current active state of this session.
- *
- * @return True if the session is active, false otherwise.
- */
- public boolean isActive() {
- return mActive;
- }
-
- /**
- * Send a proprietary event to all MediaControllers listening to this
- * Session. It's up to the Controller/Session owner to determine the meaning
- * of any events.
- *
- * @param event The name of the event to send
- * @param extras Any extras included with the event
- */
- public void sendSessionEvent(@NonNull String event, @Nullable Bundle extras) {
- if (TextUtils.isEmpty(event)) {
- throw new IllegalArgumentException("event cannot be null or empty");
- }
- try {
- mBinder.sendEvent(event, extras);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error sending event", e);
- }
- }
-
- /**
- * This must be called when an app has finished performing playback. If
- * playback is expected to start again shortly the session can be left open,
- * but it must be released if your activity or service is being destroyed.
- */
- public void release() {
- try {
- mBinder.destroy();
- } catch (RemoteException e) {
- Log.wtf(TAG, "Error releasing session: ", e);
- }
- }
-
- /**
- * Retrieve a token object that can be used by apps to create a
- * {@link MediaController} for interacting with this session. The owner of
- * the session is responsible for deciding how to distribute these tokens.
- *
- * @return A token that can be used to create a MediaController for this
- * session
- */
- public @NonNull Token getSessionToken() {
- return mSessionToken;
- }
-
- /**
- * Get a controller for this session. This is a convenience method to avoid
- * having to cache your own controller in process.
- *
- * @return A controller for this session.
- */
- public @NonNull MediaController getController() {
- return mController;
- }
-
- /**
- * Update the current playback state.
- *
- * @param state The current state of playback
- */
- public void setPlaybackState(@Nullable PlaybackState state) {
- mPlaybackState = state;
- try {
- mBinder.setPlaybackState(state);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Dead object in setPlaybackState.", e);
- }
- }
-
- /**
- * Update the current metadata. New metadata can be created using
- * {@link android.media.MediaMetadata.Builder}. This operation may take time proportional to
- * the size of the bitmap to replace large bitmaps with a scaled down copy.
- *
- * @param metadata The new metadata
- * @see android.media.MediaMetadata.Builder#putBitmap
- */
- public void setMetadata(@Nullable MediaMetadata metadata) {
- long duration = -1;
- int fields = 0;
- MediaDescription description = null;
- if (metadata != null) {
- metadata = (new MediaMetadata.Builder(metadata, mMaxBitmapSize)).build();
- if (metadata.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
- duration = metadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
- }
- fields = metadata.size();
- description = metadata.getDescription();
- }
- String metadataDescription = "size=" + fields + ", description=" + description;
-
- try {
- mBinder.setMetadata(metadata, duration, metadataDescription);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Dead object in setPlaybackState.", e);
- }
- }
-
- /**
- * Update the list of items in the play queue. It is an ordered list and
- * should contain the current item, and previous or upcoming items if they
- * exist. Specify null if there is no current play queue.
- * <p>
- * The queue should be of reasonable size. If the play queue is unbounded
- * within your app, it is better to send a reasonable amount in a sliding
- * window instead.
- *
- * @param queue A list of items in the play queue.
- */
- public void setQueue(@Nullable List<QueueItem> queue) {
- try {
- mBinder.setQueue(queue == null ? null : new MediaParceledListSlice<QueueItem>(queue));
- } catch (RemoteException e) {
- Log.wtf("Dead object in setQueue.", e);
- }
- }
-
- /**
- * Set the title of the play queue. The UI should display this title along
- * with the play queue itself.
- * e.g. "Play Queue", "Now Playing", or an album name.
- *
- * @param title The title of the play queue.
- */
- public void setQueueTitle(@Nullable CharSequence title) {
- try {
- mBinder.setQueueTitle(title);
- } catch (RemoteException e) {
- Log.wtf("Dead object in setQueueTitle.", e);
- }
- }
-
- /**
- * Set the style of rating used by this session. Apps trying to set the
- * rating should use this style. Must be one of the following:
- * <ul>
- * <li>{@link Rating#RATING_NONE}</li>
- * <li>{@link Rating#RATING_3_STARS}</li>
- * <li>{@link Rating#RATING_4_STARS}</li>
- * <li>{@link Rating#RATING_5_STARS}</li>
- * <li>{@link Rating#RATING_HEART}</li>
- * <li>{@link Rating#RATING_PERCENTAGE}</li>
- * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
- * </ul>
- */
- public void setRatingType(@Rating.Style int type) {
- try {
- mBinder.setRatingType(type);
- } catch (RemoteException e) {
- Log.e(TAG, "Error in setRatingType.", e);
- }
- }
-
- /**
- * Set some extras that can be associated with the {@link MediaSession}. No assumptions should
- * be made as to how a {@link MediaController} will handle these extras.
- * Keys should be fully qualified (e.g. com.example.MY_EXTRA) to avoid conflicts.
- *
- * @param extras The extras associated with the {@link MediaSession}.
- */
- public void setExtras(@Nullable Bundle extras) {
- try {
- mBinder.setExtras(extras);
- } catch (RemoteException e) {
- Log.wtf("Dead object in setExtras.", e);
- }
- }
-
- /**
- * Gets the controller information who sent the current request.
- * <p>
- * Note: This is only valid while in a request callback, such as {@link Callback#onPlay}.
- *
- * @throws IllegalStateException If this method is called outside of {@link Callback} methods.
- * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
- */
- public final @NonNull RemoteUserInfo getCurrentControllerInfo() {
- if (mCallback == null || mCallback.mCurrentControllerInfo == null) {
- throw new IllegalStateException(
- "This should be called inside of MediaSession.Callback methods");
- }
- return mCallback.mCurrentControllerInfo;
- }
-
- /**
- * Notify the system that the remote volume changed.
- *
- * @param provider The provider that is handling volume changes.
- * @hide
- */
- public void notifyRemoteVolumeChanged(VolumeProvider provider) {
- synchronized (mLock) {
- if (provider == null || provider != mVolumeProvider) {
- Log.w(TAG, "Received update from stale volume provider");
- return;
- }
- }
- try {
- mBinder.setCurrentVolume(provider.getCurrentVolume());
- } catch (RemoteException e) {
- Log.e(TAG, "Error in notifyVolumeChanged", e);
- }
- }
-
- /**
- * Returns the name of the package that sent the last media button, transport control, or
- * command from controllers and the system. This is only valid while in a request callback, such
- * as {@link Callback#onPlay}.
- *
- * @hide
- */
- @UnsupportedAppUsage
- public String getCallingPackage() {
- if (mCallback != null && mCallback.mCurrentControllerInfo != null) {
- return mCallback.mCurrentControllerInfo.getPackageName();
- }
- return null;
- }
-
- private void dispatchPrepare(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE, null, null);
- }
-
- private void dispatchPrepareFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_MEDIA_ID, mediaId, extras);
- }
-
- private void dispatchPrepareFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_SEARCH, query, extras);
- }
-
- private void dispatchPrepareFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREPARE_URI, uri, extras);
- }
-
- private void dispatchPlay(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY, null, null);
- }
-
- private void dispatchPlayFromMediaId(RemoteUserInfo caller, String mediaId, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_MEDIA_ID, mediaId, extras);
- }
-
- private void dispatchPlayFromSearch(RemoteUserInfo caller, String query, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_SEARCH, query, extras);
- }
-
- private void dispatchPlayFromUri(RemoteUserInfo caller, Uri uri, Bundle extras) {
- postToCallback(caller, CallbackMessageHandler.MSG_PLAY_URI, uri, extras);
- }
-
- private void dispatchSkipToItem(RemoteUserInfo caller, long id) {
- postToCallback(caller, CallbackMessageHandler.MSG_SKIP_TO_ITEM, id, null);
- }
-
- private void dispatchPause(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PAUSE, null, null);
- }
-
- private void dispatchStop(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_STOP, null, null);
- }
-
- private void dispatchNext(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_NEXT, null, null);
- }
-
- private void dispatchPrevious(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_PREVIOUS, null, null);
- }
-
- private void dispatchFastForward(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_FAST_FORWARD, null, null);
- }
-
- private void dispatchRewind(RemoteUserInfo caller) {
- postToCallback(caller, CallbackMessageHandler.MSG_REWIND, null, null);
- }
-
- private void dispatchSeekTo(RemoteUserInfo caller, long pos) {
- postToCallback(caller, CallbackMessageHandler.MSG_SEEK_TO, pos, null);
- }
-
- private void dispatchRate(RemoteUserInfo caller, Rating rating) {
- postToCallback(caller, CallbackMessageHandler.MSG_RATE, rating, null);
- }
-
- private void dispatchCustomAction(RemoteUserInfo caller, String action, Bundle args) {
- postToCallback(caller, CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args);
- }
-
- private void dispatchMediaButton(RemoteUserInfo caller, Intent mediaButtonIntent) {
- postToCallback(caller, CallbackMessageHandler.MSG_MEDIA_BUTTON, mediaButtonIntent, null);
- }
-
- private void dispatchMediaButtonDelayed(RemoteUserInfo info, Intent mediaButtonIntent,
- long delay) {
- postToCallbackDelayed(info, CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT,
- mediaButtonIntent, null, delay);
- }
-
- private void dispatchAdjustVolume(RemoteUserInfo caller, int direction) {
- postToCallback(caller, CallbackMessageHandler.MSG_ADJUST_VOLUME, direction, null);
- }
-
- private void dispatchSetVolumeTo(RemoteUserInfo caller, int volume) {
- postToCallback(caller, CallbackMessageHandler.MSG_SET_VOLUME, volume, null);
- }
-
- private void dispatchCommand(RemoteUserInfo caller, String command, Bundle args,
- ResultReceiver resultCb) {
- Command cmd = new Command(command, args, resultCb);
- postToCallback(caller, CallbackMessageHandler.MSG_COMMAND, cmd, null);
- }
-
- private void postToCallback(RemoteUserInfo caller, int what, Object obj, Bundle data) {
- postToCallbackDelayed(caller, what, obj, data, 0);
- }
-
- private void postToCallbackDelayed(RemoteUserInfo caller, int what, Object obj, Bundle data,
- long delay) {
- synchronized (mLock) {
- if (mCallback != null) {
- mCallback.post(caller, what, obj, data, delay);
- }
- }
- }
-
- /**
- * Return true if this is considered an active playback state.
- *
- * @hide
- */
- public static boolean isActiveState(int state) {
- switch (state) {
- case PlaybackState.STATE_FAST_FORWARDING:
- case PlaybackState.STATE_REWINDING:
- case PlaybackState.STATE_SKIPPING_TO_PREVIOUS:
- case PlaybackState.STATE_SKIPPING_TO_NEXT:
- case PlaybackState.STATE_BUFFERING:
- case PlaybackState.STATE_CONNECTING:
- case PlaybackState.STATE_PLAYING:
- return true;
- }
- return false;
- }
-
- /**
- * Represents an ongoing session. This may be passed to apps by the session
- * owner to allow them to create a {@link MediaController} to communicate with
- * the session.
- */
- public static final class Token implements Parcelable {
-
- private ISessionController mBinder;
-
- /**
- * @hide
- */
- public Token(ISessionController binder) {
- mBinder = binder;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeStrongBinder(mBinder.asBinder());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mBinder == null) ? 0 : mBinder.asBinder().hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Token other = (Token) obj;
- if (mBinder == null) {
- if (other.mBinder != null)
- return false;
- } else if (!mBinder.asBinder().equals(other.mBinder.asBinder()))
- return false;
- return true;
- }
-
- ISessionController getBinder() {
- return mBinder;
- }
-
- public static final Parcelable.Creator<Token> CREATOR
- = new Parcelable.Creator<Token>() {
- @Override
- public Token createFromParcel(Parcel in) {
- return new Token(ISessionController.Stub.asInterface(in.readStrongBinder()));
- }
-
- @Override
- public Token[] newArray(int size) {
- return new Token[size];
- }
- };
- }
-
- /**
- * Receives media buttons, transport controls, and commands from controllers
- * and the system. A callback may be set using {@link #setCallback}.
- */
- public abstract static class Callback {
-
- private MediaSession mSession;
- private CallbackMessageHandler mHandler;
- private boolean mMediaPlayPauseKeyPending;
-
- public Callback() {
- }
-
- /**
- * Called when a controller has sent a command to this session.
- * The owner of the session may handle custom commands but is not
- * required to.
- *
- * @param command The command name.
- * @param args Optional parameters for the command, may be null.
- * @param cb A result receiver to which a result may be sent by the command, may be null.
- */
- public void onCommand(@NonNull String command, @Nullable Bundle args,
- @Nullable ResultReceiver cb) {
- }
-
- /**
- * Called when a media button is pressed and this session has the
- * highest priority or a controller sends a media button event to the
- * session. The default behavior will call the relevant method if the
- * action for it was set.
- * <p>
- * The intent will be of type {@link Intent#ACTION_MEDIA_BUTTON} with a
- * KeyEvent in {@link Intent#EXTRA_KEY_EVENT}
- *
- * @param mediaButtonIntent an intent containing the KeyEvent as an
- * extra
- * @return True if the event was handled, false otherwise.
- */
- public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
- if (mSession != null && mHandler != null
- && Intent.ACTION_MEDIA_BUTTON.equals(mediaButtonIntent.getAction())) {
- KeyEvent ke = mediaButtonIntent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
- if (ke != null && ke.getAction() == KeyEvent.ACTION_DOWN) {
- PlaybackState state = mSession.mPlaybackState;
- long validActions = state == null ? 0 : state.getActions();
- switch (ke.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
- case KeyEvent.KEYCODE_HEADSETHOOK:
- if (ke.getRepeatCount() > 0) {
- // Consider long-press as a single tap.
- handleMediaPlayPauseKeySingleTapIfPending();
- } else if (mMediaPlayPauseKeyPending) {
- // Consider double tap as the next.
- mHandler.removeMessages(CallbackMessageHandler
- .MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
- mMediaPlayPauseKeyPending = false;
- if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
- onSkipToNext();
- }
- } else {
- mMediaPlayPauseKeyPending = true;
- mSession.dispatchMediaButtonDelayed(
- mSession.getCurrentControllerInfo(),
- mediaButtonIntent, ViewConfiguration.getDoubleTapTimeout());
- }
- return true;
- default:
- // If another key is pressed within double tap timeout, consider the
- // pending play/pause as a single tap to handle media keys in order.
- handleMediaPlayPauseKeySingleTapIfPending();
- break;
- }
-
- switch (ke.getKeyCode()) {
- case KeyEvent.KEYCODE_MEDIA_PLAY:
- if ((validActions & PlaybackState.ACTION_PLAY) != 0) {
- onPlay();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PAUSE:
- if ((validActions & PlaybackState.ACTION_PAUSE) != 0) {
- onPause();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_NEXT:
- if ((validActions & PlaybackState.ACTION_SKIP_TO_NEXT) != 0) {
- onSkipToNext();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
- if ((validActions & PlaybackState.ACTION_SKIP_TO_PREVIOUS) != 0) {
- onSkipToPrevious();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_STOP:
- if ((validActions & PlaybackState.ACTION_STOP) != 0) {
- onStop();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
- if ((validActions & PlaybackState.ACTION_FAST_FORWARD) != 0) {
- onFastForward();
- return true;
- }
- break;
- case KeyEvent.KEYCODE_MEDIA_REWIND:
- if ((validActions & PlaybackState.ACTION_REWIND) != 0) {
- onRewind();
- return true;
- }
- break;
- }
- }
- }
- return false;
- }
-
- private void handleMediaPlayPauseKeySingleTapIfPending() {
- if (!mMediaPlayPauseKeyPending) {
- return;
- }
- mMediaPlayPauseKeyPending = false;
- mHandler.removeMessages(CallbackMessageHandler.MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT);
- PlaybackState state = mSession.mPlaybackState;
- long validActions = state == null ? 0 : state.getActions();
- boolean isPlaying = state != null
- && state.getState() == PlaybackState.STATE_PLAYING;
- boolean canPlay = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
- | PlaybackState.ACTION_PLAY)) != 0;
- boolean canPause = (validActions & (PlaybackState.ACTION_PLAY_PAUSE
- | PlaybackState.ACTION_PAUSE)) != 0;
- if (isPlaying && canPause) {
- onPause();
- } else if (!isPlaying && canPlay) {
- onPlay();
- }
- }
-
- /**
- * Override to handle requests to prepare playback. During the preparation, a session should
- * not hold audio focus in order to allow other sessions play seamlessly. The state of
- * playback should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is
- * done.
- */
- public void onPrepare() {
- }
-
- /**
- * Override to handle requests to prepare for playing a specific mediaId that was provided
- * by your app's {@link MediaBrowserService}. During the preparation, a session should not
- * hold audio focus in order to allow other sessions play seamlessly. The state of playback
- * should be updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done.
- * The playback of the prepared content should start in the implementation of
- * {@link #onPlay}. Override {@link #onPlayFromMediaId} to handle requests for starting
- * playback without preparation.
- */
- public void onPrepareFromMediaId(String mediaId, Bundle extras) {
- }
-
- /**
- * Override to handle requests to prepare playback from a search query. An empty query
- * indicates that the app may prepare any music. The implementation should attempt to make a
- * smart choice about what to play. During the preparation, a session should not hold audio
- * focus in order to allow other sessions play seamlessly. The state of playback should be
- * updated to {@link PlaybackState#STATE_PAUSED} after the preparation is done. The playback
- * of the prepared content should start in the implementation of {@link #onPlay}. Override
- * {@link #onPlayFromSearch} to handle requests for starting playback without preparation.
- */
- public void onPrepareFromSearch(String query, Bundle extras) {
- }
-
- /**
- * Override to handle requests to prepare a specific media item represented by a URI.
- * During the preparation, a session should not hold audio focus in order to allow
- * other sessions play seamlessly. The state of playback should be updated to
- * {@link PlaybackState#STATE_PAUSED} after the preparation is done.
- * The playback of the prepared content should start in the implementation of
- * {@link #onPlay}. Override {@link #onPlayFromUri} to handle requests
- * for starting playback without preparation.
- */
- public void onPrepareFromUri(Uri uri, Bundle extras) {
- }
-
- /**
- * Override to handle requests to begin playback.
- */
- public void onPlay() {
- }
-
- /**
- * Override to handle requests to begin playback from a search query. An
- * empty query indicates that the app may play any music. The
- * implementation should attempt to make a smart choice about what to
- * play.
- */
- public void onPlayFromSearch(String query, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play a specific mediaId that was
- * provided by your app's {@link MediaBrowserService}.
- */
- public void onPlayFromMediaId(String mediaId, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play a specific media item represented by a URI.
- */
- public void onPlayFromUri(Uri uri, Bundle extras) {
- }
-
- /**
- * Override to handle requests to play an item with a given id from the
- * play queue.
- */
- public void onSkipToQueueItem(long id) {
- }
-
- /**
- * Override to handle requests to pause playback.
- */
- public void onPause() {
- }
-
- /**
- * Override to handle requests to skip to the next media item.
- */
- public void onSkipToNext() {
- }
-
- /**
- * Override to handle requests to skip to the previous media item.
- */
- public void onSkipToPrevious() {
- }
-
- /**
- * Override to handle requests to fast forward.
- */
- public void onFastForward() {
- }
-
- /**
- * Override to handle requests to rewind.
- */
- public void onRewind() {
- }
-
- /**
- * Override to handle requests to stop playback.
- */
- public void onStop() {
- }
-
- /**
- * Override to handle requests to seek to a specific position in ms.
- *
- * @param pos New position to move to, in milliseconds.
- */
- public void onSeekTo(long pos) {
- }
-
- /**
- * Override to handle the item being rated.
- *
- * @param rating
- */
- public void onSetRating(@NonNull Rating rating) {
- }
-
- /**
- * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be
- * performed.
- *
- * @param action The action that was originally sent in the
- * {@link PlaybackState.CustomAction}.
- * @param extras Optional extras specified by the {@link MediaController}.
- */
- public void onCustomAction(@NonNull String action, @Nullable Bundle extras) {
- }
- }
-
- /**
- * @hide
- */
- public static class CallbackStub extends ISessionCallback.Stub {
- private WeakReference<MediaSession> mMediaSession;
-
- public CallbackStub(MediaSession session) {
- mMediaSession = new WeakReference<>(session);
- }
-
- private static RemoteUserInfo createRemoteUserInfo(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- return new RemoteUserInfo(packageName, pid, uid);
- }
-
- @Override
- public void onCommand(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String command, Bundle args, ResultReceiver cb) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchCommand(createRemoteUserInfo(packageName, pid, uid, caller),
- command, args, cb);
- }
- }
-
- @Override
- public void onMediaButton(String packageName, int pid, int uid, Intent mediaButtonIntent,
- int sequenceNumber, ResultReceiver cb) {
- MediaSession session = mMediaSession.get();
- try {
- if (session != null) {
- session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, null),
- mediaButtonIntent);
- }
- } finally {
- if (cb != null) {
- cb.send(sequenceNumber, null);
- }
- }
- }
-
- @Override
- public void onMediaButtonFromController(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Intent mediaButtonIntent) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchMediaButton(createRemoteUserInfo(packageName, pid, uid, caller),
- mediaButtonIntent);
- }
- }
-
- @Override
- public void onPrepare(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepare(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPrepareFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromMediaId(
- createRemoteUserInfo(packageName, pid, uid, caller), mediaId, extras);
- }
- }
-
- @Override
- public void onPrepareFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromSearch(
- createRemoteUserInfo(packageName, pid, uid, caller), query, extras);
- }
- }
-
- @Override
- public void onPrepareFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrepareFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
- uri, extras);
- }
- }
-
- @Override
- public void onPlay(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlay(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPlayFromMediaId(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String mediaId,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromMediaId(createRemoteUserInfo(packageName, pid, uid, caller),
- mediaId, extras);
- }
- }
-
- @Override
- public void onPlayFromSearch(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String query,
- Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromSearch(createRemoteUserInfo(packageName, pid, uid, caller),
- query, extras);
- }
- }
-
- @Override
- public void onPlayFromUri(String packageName, int pid, int uid,
- ISessionControllerCallback caller, Uri uri, Bundle extras) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPlayFromUri(createRemoteUserInfo(packageName, pid, uid, caller),
- uri, extras);
- }
- }
-
- @Override
- public void onSkipToTrack(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long id) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSkipToItem(createRemoteUserInfo(packageName, pid, uid, caller), id);
- }
- }
-
- @Override
- public void onPause(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPause(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onStop(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchStop(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onNext(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchNext(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onPrevious(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchPrevious(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onFastForward(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchFastForward(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onRewind(String packageName, int pid, int uid,
- ISessionControllerCallback caller) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchRewind(createRemoteUserInfo(packageName, pid, uid, caller));
- }
- }
-
- @Override
- public void onSeekTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, long pos) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSeekTo(createRemoteUserInfo(packageName, pid, uid, caller), pos);
- }
- }
-
- @Override
- public void onRate(String packageName, int pid, int uid, ISessionControllerCallback caller,
- Rating rating) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchRate(createRemoteUserInfo(packageName, pid, uid, caller), rating);
- }
- }
-
- @Override
- public void onCustomAction(String packageName, int pid, int uid,
- ISessionControllerCallback caller, String action, Bundle args) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchCustomAction(createRemoteUserInfo(packageName, pid, uid, caller),
- action, args);
- }
- }
-
- @Override
- public void onAdjustVolume(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int direction) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchAdjustVolume(createRemoteUserInfo(packageName, pid, uid, caller),
- direction);
- }
- }
-
- @Override
- public void onSetVolumeTo(String packageName, int pid, int uid,
- ISessionControllerCallback caller, int value) {
- MediaSession session = mMediaSession.get();
- if (session != null) {
- session.dispatchSetVolumeTo(createRemoteUserInfo(packageName, pid, uid, caller),
- value);
- }
- }
- }
-
- /**
- * 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 QueueItem implements Parcelable {
- /**
- * This id is reserved. No items can be explicitly assigned this id.
- */
- public static final int UNKNOWN_ID = -1;
-
- private final MediaDescription mDescription;
- @UnsupportedAppUsage
- private final long mId;
-
- /**
- * Create a new {@link MediaSession.QueueItem}.
- *
- * @param description The {@link MediaDescription} for this item.
- * @param id An identifier for this item. It must be unique within the
- * play queue and cannot be {@link #UNKNOWN_ID}.
- */
- 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;
- }
-
- private QueueItem(Parcel in) {
- mDescription = MediaDescription.CREATOR.createFromParcel(in);
- mId = in.readLong();
- }
-
- /**
- * Get the description for this item.
- */
- public MediaDescription getDescription() {
- return mDescription;
- }
-
- /**
- * Get the queue id for this item.
- */
- public long getQueueId() {
- return mId;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- mDescription.writeToParcel(dest, flags);
- dest.writeLong(mId);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Creator<MediaSession.QueueItem> CREATOR =
- new Creator<MediaSession.QueueItem>() {
-
- @Override
- public MediaSession.QueueItem createFromParcel(Parcel p) {
- return new MediaSession.QueueItem(p);
- }
-
- @Override
- public MediaSession.QueueItem[] newArray(int size) {
- return new MediaSession.QueueItem[size];
- }
- };
-
- @Override
- public String toString() {
- return "MediaSession.QueueItem {" +
- "Description=" + mDescription +
- ", Id=" + mId + " }";
- }
-
- @Override
- public boolean equals(Object o) {
- if (o == null) {
- return false;
- }
-
- if (!(o instanceof QueueItem)) {
- return false;
- }
-
- final QueueItem item = (QueueItem) o;
- if (mId != item.mId) {
- return false;
- }
-
- if (!Objects.equals(mDescription, item.mDescription)) {
- return false;
- }
-
- return true;
- }
- }
-
- private static final class Command {
- public final String command;
- public final Bundle extras;
- public final ResultReceiver stub;
-
- public Command(String command, Bundle extras, ResultReceiver stub) {
- this.command = command;
- this.extras = extras;
- this.stub = stub;
- }
- }
-
- private class CallbackMessageHandler extends Handler {
- private static final int MSG_COMMAND = 1;
- private static final int MSG_MEDIA_BUTTON = 2;
- private static final int MSG_PREPARE = 3;
- private static final int MSG_PREPARE_MEDIA_ID = 4;
- private static final int MSG_PREPARE_SEARCH = 5;
- private static final int MSG_PREPARE_URI = 6;
- private static final int MSG_PLAY = 7;
- private static final int MSG_PLAY_MEDIA_ID = 8;
- private static final int MSG_PLAY_SEARCH = 9;
- private static final int MSG_PLAY_URI = 10;
- private static final int MSG_SKIP_TO_ITEM = 11;
- private static final int MSG_PAUSE = 12;
- private static final int MSG_STOP = 13;
- private static final int MSG_NEXT = 14;
- private static final int MSG_PREVIOUS = 15;
- private static final int MSG_FAST_FORWARD = 16;
- private static final int MSG_REWIND = 17;
- private static final int MSG_SEEK_TO = 18;
- private static final int MSG_RATE = 19;
- private static final int MSG_CUSTOM_ACTION = 20;
- private static final int MSG_ADJUST_VOLUME = 21;
- private static final int MSG_SET_VOLUME = 22;
- private static final int MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT = 23;
-
- private MediaSession.Callback mCallback;
- private RemoteUserInfo mCurrentControllerInfo;
-
- public CallbackMessageHandler(Looper looper, MediaSession.Callback callback) {
- super(looper);
- mCallback = callback;
- mCallback.mHandler = this;
- }
-
- public void post(RemoteUserInfo caller, int what, Object obj, Bundle data, long delayMs) {
- Pair<RemoteUserInfo, Object> objWithCaller = Pair.create(caller, obj);
- Message msg = obtainMessage(what, objWithCaller);
- msg.setAsynchronous(true);
- msg.setData(data);
- if (delayMs > 0) {
- sendMessageDelayed(msg, delayMs);
- } else {
- sendMessage(msg);
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- mCurrentControllerInfo = ((Pair<RemoteUserInfo, Object>) msg.obj).first;
-
- VolumeProvider vp;
- Object obj = ((Pair<RemoteUserInfo, Object>) msg.obj).second;
-
- switch (msg.what) {
- case MSG_COMMAND:
- Command cmd = (Command) obj;
- mCallback.onCommand(cmd.command, cmd.extras, cmd.stub);
- break;
- case MSG_MEDIA_BUTTON:
- mCallback.onMediaButtonEvent((Intent) obj);
- break;
- case MSG_PREPARE:
- mCallback.onPrepare();
- break;
- case MSG_PREPARE_MEDIA_ID:
- mCallback.onPrepareFromMediaId((String) obj, msg.getData());
- break;
- case MSG_PREPARE_SEARCH:
- mCallback.onPrepareFromSearch((String) obj, msg.getData());
- break;
- case MSG_PREPARE_URI:
- mCallback.onPrepareFromUri((Uri) obj, msg.getData());
- break;
- case MSG_PLAY:
- mCallback.onPlay();
- break;
- case MSG_PLAY_MEDIA_ID:
- mCallback.onPlayFromMediaId((String) obj, msg.getData());
- break;
- case MSG_PLAY_SEARCH:
- mCallback.onPlayFromSearch((String) obj, msg.getData());
- break;
- case MSG_PLAY_URI:
- mCallback.onPlayFromUri((Uri) obj, msg.getData());
- break;
- case MSG_SKIP_TO_ITEM:
- mCallback.onSkipToQueueItem((Long) obj);
- break;
- case MSG_PAUSE:
- mCallback.onPause();
- break;
- case MSG_STOP:
- mCallback.onStop();
- break;
- case MSG_NEXT:
- mCallback.onSkipToNext();
- break;
- case MSG_PREVIOUS:
- mCallback.onSkipToPrevious();
- break;
- case MSG_FAST_FORWARD:
- mCallback.onFastForward();
- break;
- case MSG_REWIND:
- mCallback.onRewind();
- break;
- case MSG_SEEK_TO:
- mCallback.onSeekTo((Long) obj);
- break;
- case MSG_RATE:
- mCallback.onSetRating((Rating) obj);
- break;
- case MSG_CUSTOM_ACTION:
- mCallback.onCustomAction((String) obj, msg.getData());
- break;
- case MSG_ADJUST_VOLUME:
- synchronized (mLock) {
- vp = mVolumeProvider;
- }
- if (vp != null) {
- vp.onAdjustVolume((int) obj);
- }
- break;
- case MSG_SET_VOLUME:
- synchronized (mLock) {
- vp = mVolumeProvider;
- }
- if (vp != null) {
- vp.onSetVolumeTo((int) obj);
- }
- break;
- case MSG_PLAY_PAUSE_KEY_DOUBLE_TAP_TIMEOUT:
- mCallback.handleMediaPlayPauseKeySingleTapIfPending();
- break;
- }
- mCurrentControllerInfo = null;
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
deleted file mode 100644
index c4250f0..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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.session;
-
-parcelable ParcelableVolumeInfo;
diff --git a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java b/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
deleted file mode 100644
index f59c975..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/ParcelableVolumeInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/* 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.session;
-
-import android.media.AudioAttributes;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Convenience class for passing information about the audio configuration of a
- * session. The public implementation is {@link MediaController.PlaybackInfo}.
- *
- * @hide
- */
-public class ParcelableVolumeInfo implements Parcelable {
- public int volumeType;
- public AudioAttributes audioAttrs;
- public int controlType;
- public int maxVolume;
- public int currentVolume;
-
- public ParcelableVolumeInfo(int volumeType, AudioAttributes audioAttrs, int controlType,
- int maxVolume,
- int currentVolume) {
- this.volumeType = volumeType;
- this.audioAttrs = audioAttrs;
- this.controlType = controlType;
- this.maxVolume = maxVolume;
- this.currentVolume = currentVolume;
- }
-
- public ParcelableVolumeInfo(Parcel from) {
- volumeType = from.readInt();
- controlType = from.readInt();
- maxVolume = from.readInt();
- currentVolume = from.readInt();
- audioAttrs = AudioAttributes.CREATOR.createFromParcel(from);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(volumeType);
- dest.writeInt(controlType);
- dest.writeInt(maxVolume);
- dest.writeInt(currentVolume);
- audioAttrs.writeToParcel(dest, flags);
- }
-
-
- public static final Parcelable.Creator<ParcelableVolumeInfo> CREATOR
- = new Parcelable.Creator<ParcelableVolumeInfo>() {
- @Override
- public ParcelableVolumeInfo createFromParcel(Parcel in) {
- return new ParcelableVolumeInfo(in);
- }
-
- @Override
- public ParcelableVolumeInfo[] newArray(int size) {
- return new ParcelableVolumeInfo[size];
- }
- };
-}
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
deleted file mode 100644
index 0876ebd..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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.session;
-
-parcelable PlaybackState;
diff --git a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java b/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
deleted file mode 100644
index ed4f9af..0000000
--- a/packages/MediaComponents/apex/java/android/media/session/PlaybackState.java
+++ /dev/null
@@ -1,1081 +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.session;
-
-import android.annotation.DrawableRes;
-import android.annotation.IntDef;
-import android.annotation.LongDef;
-import android.annotation.Nullable;
-import android.media.RemoteControlClient;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import java.util.ArrayList;
-import java.util.List;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Playback state for a {@link MediaSession}. This includes a state like
- * {@link PlaybackState#STATE_PLAYING}, the current playback position,
- * and the current control capabilities.
- */
-public final class PlaybackState implements Parcelable {
- private static final String TAG = "PlaybackState";
-
- /**
- * @hide
- */
- @LongDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
- ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
- ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
- ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
- ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
- @Retention(RetentionPolicy.SOURCE)
- public @interface Actions {}
-
- /**
- * Indicates this session supports the stop command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_STOP = 1 << 0;
-
- /**
- * Indicates this session supports the pause command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PAUSE = 1 << 1;
-
- /**
- * Indicates this session supports the play command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY = 1 << 2;
-
- /**
- * Indicates this session supports the rewind command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_REWIND = 1 << 3;
-
- /**
- * Indicates this session supports the previous command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_PREVIOUS = 1 << 4;
-
- /**
- * Indicates this session supports the next command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_NEXT = 1 << 5;
-
- /**
- * Indicates this session supports the fast forward command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_FAST_FORWARD = 1 << 6;
-
- /**
- * Indicates this session supports the set rating command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SET_RATING = 1 << 7;
-
- /**
- * Indicates this session supports the seek to command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SEEK_TO = 1 << 8;
-
- /**
- * Indicates this session supports the play/pause toggle command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_PAUSE = 1 << 9;
-
- /**
- * Indicates this session supports the play from media id command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_FROM_MEDIA_ID = 1 << 10;
-
- /**
- * 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 session supports the skip to queue item command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_SKIP_TO_QUEUE_ITEM = 1 << 12;
-
- /**
- * Indicates this session supports the play from URI command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PLAY_FROM_URI = 1 << 13;
-
- /**
- * Indicates this session supports the prepare command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE = 1 << 14;
-
- /**
- * Indicates this session supports the prepare from media id command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_MEDIA_ID = 1 << 15;
-
- /**
- * Indicates this session supports the prepare from search command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_SEARCH = 1 << 16;
-
- /**
- * Indicates this session supports the prepare from URI command.
- *
- * @see Builder#setActions(long)
- */
- public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
-
- /**
- * @hide
- */
- @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
- STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
- STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
- @Retention(RetentionPolicy.SOURCE)
- public @interface State {}
-
- /**
- * This is the default playback state and indicates that no media has been
- * added yet, or the performer has been reset and has no content to play.
- *
- * @see Builder#setState(int, long, float)
- * @see Builder#setState(int, long, float, long)
- */
- public final static int STATE_NONE = 0;
-
- /**
- * State indicating this item is currently stopped.
- *
- * @see Builder#setState
- */
- public final static int STATE_STOPPED = 1;
-
- /**
- * State indicating this item is currently paused.
- *
- * @see Builder#setState
- */
- public final static int STATE_PAUSED = 2;
-
- /**
- * State indicating this item is currently playing.
- *
- * @see Builder#setState
- */
- public final static int STATE_PLAYING = 3;
-
- /**
- * State indicating this item is currently fast forwarding.
- *
- * @see Builder#setState
- */
- public final static int STATE_FAST_FORWARDING = 4;
-
- /**
- * State indicating this item is currently rewinding.
- *
- * @see Builder#setState
- */
- public final static int STATE_REWINDING = 5;
-
- /**
- * State indicating this item is currently buffering and will begin playing
- * when enough data has buffered.
- *
- * @see Builder#setState
- */
- public final static int STATE_BUFFERING = 6;
-
- /**
- * State indicating this item is currently in an error state. The error
- * message should also be set when entering this state.
- *
- * @see Builder#setState
- */
- public final static int STATE_ERROR = 7;
-
- /**
- * State indicating the class doing playback is currently connecting to a
- * new destination. Depending on the implementation you may return to the previous
- * state when the connection finishes or enter {@link #STATE_NONE}.
- * If the connection failed {@link #STATE_ERROR} should be used.
- *
- * @see Builder#setState
- */
- public final static int STATE_CONNECTING = 8;
-
- /**
- * State indicating the player is currently skipping to the previous item.
- *
- * @see Builder#setState
- */
- public final static int STATE_SKIPPING_TO_PREVIOUS = 9;
-
- /**
- * State indicating the player is currently skipping to the next item.
- *
- * @see Builder#setState
- */
- 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;
-
- private final int mState;
- private final long mPosition;
- private final long mBufferedPosition;
- private final float mSpeed;
- private final long mActions;
- private List<PlaybackState.CustomAction> mCustomActions;
- private final CharSequence mErrorMessage;
- private final long mUpdateTime;
- private final long mActiveItemId;
- private final Bundle mExtras;
-
- private PlaybackState(int state, long position, long updateTime, float speed,
- long bufferedPosition, long transportControls,
- List<PlaybackState.CustomAction> customActions, long activeItemId,
- CharSequence error, Bundle extras) {
- mState = state;
- mPosition = position;
- mSpeed = speed;
- mUpdateTime = updateTime;
- mBufferedPosition = bufferedPosition;
- mActions = transportControls;
- mCustomActions = new ArrayList<>(customActions);
- mActiveItemId = activeItemId;
- mErrorMessage = error;
- mExtras = extras;
- }
-
- private PlaybackState(Parcel in) {
- mState = in.readInt();
- mPosition = in.readLong();
- mSpeed = in.readFloat();
- mUpdateTime = in.readLong();
- mBufferedPosition = in.readLong();
- mActions = in.readLong();
- mCustomActions = in.createTypedArrayList(CustomAction.CREATOR);
- mActiveItemId = in.readLong();
- mErrorMessage = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mExtras = in.readBundle();
- }
-
- @Override
- public String toString() {
- StringBuilder bob = new StringBuilder("PlaybackState {");
- bob.append("state=").append(mState);
- bob.append(", position=").append(mPosition);
- bob.append(", buffered position=").append(mBufferedPosition);
- bob.append(", speed=").append(mSpeed);
- bob.append(", updated=").append(mUpdateTime);
- bob.append(", actions=").append(mActions);
- bob.append(", custom actions=").append(mCustomActions);
- bob.append(", active item id=").append(mActiveItemId);
- bob.append(", error=").append(mErrorMessage);
- bob.append("}");
- return bob.toString();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mState);
- dest.writeLong(mPosition);
- dest.writeFloat(mSpeed);
- dest.writeLong(mUpdateTime);
- dest.writeLong(mBufferedPosition);
- dest.writeLong(mActions);
- dest.writeTypedList(mCustomActions);
- dest.writeLong(mActiveItemId);
- TextUtils.writeToParcel(mErrorMessage, dest, 0);
- dest.writeBundle(mExtras);
- }
-
- /**
- * Get the current state of playback. One of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- */
- @State
- public int getState() {
- return mState;
- }
-
- /**
- * Get the current playback position in ms.
- */
- public long getPosition() {
- return mPosition;
- }
-
- /**
- * Get the current buffered position in ms. This is the farthest playback
- * point that can be reached from the current position using only buffered
- * content.
- */
- public long getBufferedPosition() {
- return mBufferedPosition;
- }
-
- /**
- * Get the current playback speed as a multiple of normal playback. This
- * should be negative when rewinding. A value of 1 means normal playback and
- * 0 means paused.
- *
- * @return The current speed of playback.
- */
- public float getPlaybackSpeed() {
- return mSpeed;
- }
-
- /**
- * Get the current actions available on this session. This should use a
- * bitmask of the available actions.
- * <ul>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#ACTION_REWIND}</li>
- * <li> {@link PlaybackState#ACTION_PLAY}</li>
- * <li> {@link PlaybackState#ACTION_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_STOP}</li>
- * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
- * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
- * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
- * </ul>
- */
- @Actions
- public long getActions() {
- return mActions;
- }
-
- /**
- * Get the list of custom actions.
- */
- public List<PlaybackState.CustomAction> getCustomActions() {
- return mCustomActions;
- }
-
- /**
- * Get a user readable error message. This should be set when the state is
- * {@link PlaybackState#STATE_ERROR}.
- */
- public CharSequence getErrorMessage() {
- return mErrorMessage;
- }
-
- /**
- * Get the elapsed real time at which position was last updated. If the
- * position has never been set this will return 0;
- *
- * @return The last time the position was updated.
- */
- public long getLastPositionUpdateTime() {
- return mUpdateTime;
- }
-
- /**
- * 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 any custom extras that were set on this playback state.
- *
- * @return The extras for this state or null.
- */
- public @Nullable Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Get the {@link PlaybackState} state for the given
- * {@link RemoteControlClient} state.
- *
- * @param rccState The state used by {@link RemoteControlClient}.
- * @return The equivalent state used by {@link PlaybackState}.
- * @hide
- */
- public static int getStateFromRccState(int rccState) {
- switch (rccState) {
- case RemoteControlClient.PLAYSTATE_BUFFERING:
- return STATE_BUFFERING;
- case RemoteControlClient.PLAYSTATE_ERROR:
- return STATE_ERROR;
- case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
- return STATE_FAST_FORWARDING;
- //RemoteControlClient.PLAYSTATE_NONE is hidden
- case 0: //RemoteControlClient.PLAYSTATE_NONE:
- return STATE_NONE;
- case RemoteControlClient.PLAYSTATE_PAUSED:
- return STATE_PAUSED;
- case RemoteControlClient.PLAYSTATE_PLAYING:
- return STATE_PLAYING;
- case RemoteControlClient.PLAYSTATE_REWINDING:
- return STATE_REWINDING;
- case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
- return STATE_SKIPPING_TO_PREVIOUS;
- case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
- return STATE_SKIPPING_TO_NEXT;
- case RemoteControlClient.PLAYSTATE_STOPPED:
- return STATE_STOPPED;
- default:
- return -1;
- }
- }
-
- /**
- * Get the {@link RemoteControlClient} state for the given
- * {@link PlaybackState} state.
- *
- * @param state The state used by {@link PlaybackState}.
- * @return The equivalent state used by {@link RemoteControlClient}.
- * @hide
- */
- public static int getRccStateFromState(int state) {
- switch (state) {
- case STATE_BUFFERING:
- return RemoteControlClient.PLAYSTATE_BUFFERING;
- case STATE_ERROR:
- return RemoteControlClient.PLAYSTATE_ERROR;
- case STATE_FAST_FORWARDING:
- return RemoteControlClient.PLAYSTATE_FAST_FORWARDING;
- case STATE_NONE:
- //RemoteControlClient.PLAYSTATE_NONE is hidden
- return 0; //RemoteControlClient.PLAYSTATE_NONE;
- case STATE_PAUSED:
- return RemoteControlClient.PLAYSTATE_PAUSED;
- case STATE_PLAYING:
- return RemoteControlClient.PLAYSTATE_PLAYING;
- case STATE_REWINDING:
- return RemoteControlClient.PLAYSTATE_REWINDING;
- case STATE_SKIPPING_TO_PREVIOUS:
- return RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS;
- case STATE_SKIPPING_TO_NEXT:
- return RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS;
- case STATE_STOPPED:
- return RemoteControlClient.PLAYSTATE_STOPPED;
- default:
- return -1;
- }
- }
-
- /**
- * @hide
- */
- public static long getActionsFromRccControlFlags(int rccFlags) {
- long actions = 0;
- long flag = 1;
- while (flag <= rccFlags) {
- if ((flag & rccFlags) != 0) {
- actions |= getActionForRccFlag((int) flag);
- }
- flag = flag << 1;
- }
- return actions;
- }
-
- /**
- * @hide
- */
- public static int getRccControlFlagsFromActions(long actions) {
- int rccFlags = 0;
- long action = 1;
- while (action <= actions && action < Integer.MAX_VALUE) {
- if ((action & actions) != 0) {
- rccFlags |= getRccFlagForAction(action);
- }
- action = action << 1;
- }
- return rccFlags;
- }
-
- private static long getActionForRccFlag(int flag) {
- switch (flag) {
- case RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS:
- return ACTION_SKIP_TO_PREVIOUS;
- case RemoteControlClient.FLAG_KEY_MEDIA_REWIND:
- return ACTION_REWIND;
- case RemoteControlClient.FLAG_KEY_MEDIA_PLAY:
- return ACTION_PLAY;
- case RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE:
- return ACTION_PLAY_PAUSE;
- case RemoteControlClient.FLAG_KEY_MEDIA_PAUSE:
- return ACTION_PAUSE;
- case RemoteControlClient.FLAG_KEY_MEDIA_STOP:
- return ACTION_STOP;
- case RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD:
- return ACTION_FAST_FORWARD;
- case RemoteControlClient.FLAG_KEY_MEDIA_NEXT:
- return ACTION_SKIP_TO_NEXT;
- case RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE:
- return ACTION_SEEK_TO;
- case RemoteControlClient.FLAG_KEY_MEDIA_RATING:
- return ACTION_SET_RATING;
- }
- return 0;
- }
-
- private static int getRccFlagForAction(long action) {
- // We only care about the lower set of actions that can map to rcc
- // flags.
- int testAction = action < Integer.MAX_VALUE ? (int) action : 0;
- switch (testAction) {
- case (int) ACTION_SKIP_TO_PREVIOUS:
- return RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS;
- case (int) ACTION_REWIND:
- return RemoteControlClient.FLAG_KEY_MEDIA_REWIND;
- case (int) ACTION_PLAY:
- return RemoteControlClient.FLAG_KEY_MEDIA_PLAY;
- case (int) ACTION_PLAY_PAUSE:
- return RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE;
- case (int) ACTION_PAUSE:
- return RemoteControlClient.FLAG_KEY_MEDIA_PAUSE;
- case (int) ACTION_STOP:
- return RemoteControlClient.FLAG_KEY_MEDIA_STOP;
- case (int) ACTION_FAST_FORWARD:
- return RemoteControlClient.FLAG_KEY_MEDIA_FAST_FORWARD;
- case (int) ACTION_SKIP_TO_NEXT:
- return RemoteControlClient.FLAG_KEY_MEDIA_NEXT;
- case (int) ACTION_SEEK_TO:
- return RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
- case (int) ACTION_SET_RATING:
- return RemoteControlClient.FLAG_KEY_MEDIA_RATING;
- }
- return 0;
- }
-
- public static final Parcelable.Creator<PlaybackState> CREATOR =
- new Parcelable.Creator<PlaybackState>() {
- @Override
- public PlaybackState createFromParcel(Parcel in) {
- return new PlaybackState(in);
- }
-
- @Override
- public PlaybackState[] newArray(int size) {
- return new PlaybackState[size];
- }
- };
-
- /**
- * {@link PlaybackState.CustomAction CustomActions} can be used to extend the capabilities of
- * the standard transport controls by exposing app specific actions to
- * {@link MediaController MediaControllers}.
- */
- public static final class CustomAction implements Parcelable {
- private final String mAction;
- private final CharSequence mName;
- private final int mIcon;
- private final Bundle mExtras;
-
- /**
- * Use {@link PlaybackState.CustomAction.Builder#build()}.
- */
- private CustomAction(String action, CharSequence name, int icon, Bundle extras) {
- mAction = action;
- mName = name;
- mIcon = icon;
- mExtras = extras;
- }
-
- private CustomAction(Parcel in) {
- mAction = in.readString();
- mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mIcon = in.readInt();
- mExtras = in.readBundle();
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeString(mAction);
- TextUtils.writeToParcel(mName, dest, flags);
- dest.writeInt(mIcon);
- dest.writeBundle(mExtras);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<PlaybackState.CustomAction> CREATOR
- = new Parcelable.Creator<PlaybackState.CustomAction>() {
-
- @Override
- public PlaybackState.CustomAction createFromParcel(Parcel p) {
- return new PlaybackState.CustomAction(p);
- }
-
- @Override
- public PlaybackState.CustomAction[] newArray(int size) {
- return new PlaybackState.CustomAction[size];
- }
- };
-
- /**
- * Returns the action of the {@link CustomAction}.
- *
- * @return The action of the {@link CustomAction}.
- */
- public String getAction() {
- return mAction;
- }
-
- /**
- * Returns the display name of this action. e.g. "Favorite"
- *
- * @return The display name of this {@link CustomAction}.
- */
- public CharSequence getName() {
- return mName;
- }
-
- /**
- * Returns the resource id of the icon in the {@link MediaSession MediaSession's} package.
- *
- * @return The resource id of the icon in the {@link MediaSession MediaSession's} package.
- */
- public int getIcon() {
- return mIcon;
- }
-
- /**
- * Returns extras which provide additional application-specific information about the
- * action, or null if none. These arguments are meant to be consumed by a
- * {@link MediaController} if it knows how to handle them.
- *
- * @return Optional arguments for the {@link CustomAction}.
- */
- public Bundle getExtras() {
- return mExtras;
- }
-
- @Override
- public String toString() {
- return "Action:" +
- "mName='" + mName +
- ", mIcon=" + mIcon +
- ", mExtras=" + mExtras;
- }
-
- /**
- * Builder for {@link CustomAction} objects.
- */
- public static final class Builder {
- private final String mAction;
- private final CharSequence mName;
- private final int mIcon;
- private Bundle mExtras;
-
- /**
- * Creates a {@link CustomAction} builder with the id, name, and icon set.
- *
- * @param action The action of the {@link CustomAction}.
- * @param name The display name of the {@link CustomAction}. This name will be displayed
- * along side the action if the UI supports it.
- * @param icon The icon resource id of the {@link CustomAction}. This resource id
- * must be in the same package as the {@link MediaSession}. It will be
- * displayed with the custom action if the UI supports it.
- */
- public Builder(String action, CharSequence name, @DrawableRes int icon) {
- if (TextUtils.isEmpty(action)) {
- throw new IllegalArgumentException(
- "You must specify an action to build a CustomAction.");
- }
- if (TextUtils.isEmpty(name)) {
- throw new IllegalArgumentException(
- "You must specify a name to build a CustomAction.");
- }
- if (icon == 0) {
- throw new IllegalArgumentException(
- "You must specify an icon resource id to build a CustomAction.");
- }
- mAction = action;
- mName = name;
- mIcon = icon;
- }
-
- /**
- * Set optional extras for the {@link CustomAction}. These extras are meant to be
- * consumed by a {@link MediaController} if it knows how to handle them.
- * Keys should be fully qualified (e.g. "com.example.MY_ARG") to avoid collisions.
- *
- * @param extras Optional extras for the {@link CustomAction}.
- * @return this.
- */
- public Builder setExtras(Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * Build and return the {@link CustomAction} instance with the specified values.
- *
- * @return A new {@link CustomAction} instance.
- */
- public CustomAction build() {
- return new CustomAction(mAction, mName, mIcon, mExtras);
- }
- }
- }
-
- /**
- * Builder for {@link PlaybackState} objects.
- */
- public static final class Builder {
- private final List<PlaybackState.CustomAction> mCustomActions = new ArrayList<>();
-
- private int mState;
- private long mPosition;
- private long mBufferedPosition;
- private float mSpeed;
- private long mActions;
- private CharSequence mErrorMessage;
- private long mUpdateTime;
- private long mActiveItemId = MediaSession.QueueItem.UNKNOWN_ID;
- private Bundle mExtras;
-
- /**
- * Creates an initially empty state builder.
- */
- public Builder() {
- }
-
- /**
- * Creates a builder with the same initial values as those in the from
- * state.
- *
- * @param from The state to use for initializing the builder.
- */
- public Builder(PlaybackState from) {
- if (from == null) {
- return;
- }
- mState = from.mState;
- mPosition = from.mPosition;
- mBufferedPosition = from.mBufferedPosition;
- mSpeed = from.mSpeed;
- mActions = from.mActions;
- if (from.mCustomActions != null) {
- mCustomActions.addAll(from.mCustomActions);
- }
- mErrorMessage = from.mErrorMessage;
- mUpdateTime = from.mUpdateTime;
- mActiveItemId = from.mActiveItemId;
- mExtras = from.mExtras;
- }
-
- /**
- * Set the current state of playback.
- * <p>
- * The position must be in ms and indicates the current playback
- * position within the item. If the position is unknown use
- * {@link #PLAYBACK_POSITION_UNKNOWN}. When not using an unknown
- * position the time at which the position was updated must be provided.
- * It is okay to use {@link SystemClock#elapsedRealtime()} if the
- * current position was just retrieved.
- * <p>
- * The speed is a multiple of normal playback and should be 0 when
- * paused and negative when rewinding. Normal playback speed is 1.0.
- * <p>
- * The state must be one of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- *
- * @param state The current state of playback.
- * @param position The position in the current item in ms.
- * @param playbackSpeed The current speed of playback as a multiple of
- * normal playback.
- * @param updateTime The time in the {@link SystemClock#elapsedRealtime}
- * timebase that the position was updated at.
- * @return this
- */
- public Builder setState(@State int state, long position, float playbackSpeed,
- long updateTime) {
- mState = state;
- mPosition = position;
- mUpdateTime = updateTime;
- mSpeed = playbackSpeed;
- return this;
- }
-
- /**
- * Set the current state of playback.
- * <p>
- * The position must be in ms and indicates the current playback
- * position within the item. If the position is unknown use
- * {@link #PLAYBACK_POSITION_UNKNOWN}. The update time will be set to
- * the current {@link SystemClock#elapsedRealtime()}.
- * <p>
- * The speed is a multiple of normal playback and should be 0 when
- * paused and negative when rewinding. Normal playback speed is 1.0.
- * <p>
- * The state must be one of the following:
- * <ul>
- * <li> {@link PlaybackState#STATE_NONE}</li>
- * <li> {@link PlaybackState#STATE_STOPPED}</li>
- * <li> {@link PlaybackState#STATE_PLAYING}</li>
- * <li> {@link PlaybackState#STATE_PAUSED}</li>
- * <li> {@link PlaybackState#STATE_FAST_FORWARDING}</li>
- * <li> {@link PlaybackState#STATE_REWINDING}</li>
- * <li> {@link PlaybackState#STATE_BUFFERING}</li>
- * <li> {@link PlaybackState#STATE_ERROR}</li>
- * <li> {@link PlaybackState#STATE_CONNECTING}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_NEXT}</li>
- * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
- * </ul>
- *
- * @param state The current state of playback.
- * @param position The position in the current item in ms.
- * @param playbackSpeed The current speed of playback as a multiple of
- * normal playback.
- * @return this
- */
- public Builder setState(@State int state, long position, float playbackSpeed) {
- return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
- }
-
- /**
- * Set the current actions available on this session. This should use a
- * bitmask of possible actions.
- * <ul>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_PREVIOUS}</li>
- * <li> {@link PlaybackState#ACTION_REWIND}</li>
- * <li> {@link PlaybackState#ACTION_PLAY}</li>
- * <li> {@link PlaybackState#ACTION_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_STOP}</li>
- * <li> {@link PlaybackState#ACTION_FAST_FORWARD}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_NEXT}</li>
- * <li> {@link PlaybackState#ACTION_SEEK_TO}</li>
- * <li> {@link PlaybackState#ACTION_SET_RATING}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_PAUSE}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_SKIP_TO_QUEUE_ITEM}</li>
- * <li> {@link PlaybackState#ACTION_PLAY_FROM_URI}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}</li>
- * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
- * </ul>
- *
- * @param actions The set of actions allowed.
- * @return this
- */
- public Builder setActions(@Actions long actions) {
- mActions = actions;
- return this;
- }
-
- /**
- * Add a custom action to the playback state. Actions can be used to
- * expose additional functionality to {@link MediaController
- * MediaControllers} beyond what is offered by the standard transport
- * controls.
- * <p>
- * e.g. start a radio station based on the current item or skip ahead by
- * 30 seconds.
- *
- * @param action An identifier for this action. It can be sent back to
- * the {@link MediaSession} through
- * {@link MediaController.TransportControls#sendCustomAction(String, Bundle)}.
- * @param name The display name for the action. If text is shown with
- * the action or used for accessibility, this is what should
- * be used.
- * @param icon The resource action of the icon that should be displayed
- * for the action. The resource should be in the package of
- * the {@link MediaSession}.
- * @return this
- */
- public Builder addCustomAction(String action, String name, int icon) {
- return addCustomAction(new PlaybackState.CustomAction(action, name, icon, null));
- }
-
- /**
- * Add a custom action to the playback state. Actions can be used to expose additional
- * functionality to {@link MediaController MediaControllers} beyond what is offered by the
- * standard transport controls.
- * <p>
- * An example of an action would be to start a radio station based on the current item
- * or to skip ahead by 30 seconds.
- *
- * @param customAction The custom action to add to the {@link PlaybackState}.
- * @return this
- */
- public Builder addCustomAction(PlaybackState.CustomAction customAction) {
- if (customAction == null) {
- throw new IllegalArgumentException(
- "You may not add a null CustomAction to PlaybackState.");
- }
- mCustomActions.add(customAction);
- return this;
- }
-
- /**
- * Set the current buffered position in ms. This is the farthest
- * playback point that can be reached from the current position using
- * only buffered content.
- *
- * @param bufferedPosition The position in ms that playback is buffered
- * to.
- * @return this
- */
- public Builder setBufferedPosition(long bufferedPosition) {
- mBufferedPosition = bufferedPosition;
- return this;
- }
-
- /**
- * Set the active item in the play queue by specifying its id. The
- * default value is {@link MediaSession.QueueItem#UNKNOWN_ID}
- *
- * @param id The id of the active item.
- * @return this
- */
- public Builder setActiveQueueItemId(long id) {
- mActiveItemId = id;
- return this;
- }
-
- /**
- * Set a user readable error message. This should be set when the state
- * is {@link PlaybackState#STATE_ERROR}.
- *
- * @param error The error message for display to the user.
- * @return this
- */
- public Builder setErrorMessage(CharSequence error) {
- mErrorMessage = error;
- return this;
- }
-
- /**
- * Set any custom extras to be included with the playback state.
- *
- * @param extras The extras to include.
- * @return this
- */
- public Builder setExtras(Bundle extras) {
- mExtras = extras;
- return this;
- }
-
- /**
- * Build and return the {@link PlaybackState} instance with these
- * values.
- *
- * @return A new state instance.
- */
- public PlaybackState build() {
- return new PlaybackState(mState, mPosition, mUpdateTime, mSpeed, mBufferedPosition,
- mActions, mCustomActions, mActiveItemId, mErrorMessage, mExtras);
- }
- }
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
deleted file mode 100644
index 84f41f6..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserService.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.content.res.Configuration;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.ResultReceiver;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserService {
- void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
- void disconnect(IMediaBrowserServiceCallbacks callbacks);
-
- void addSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
- void removeSubscriptionDeprecated(String uri, IMediaBrowserServiceCallbacks callbacks);
-
- void getMediaItem(String uri, in ResultReceiver cb, IMediaBrowserServiceCallbacks callbacks);
- void addSubscription(String uri, in IBinder token, in Bundle options,
- IMediaBrowserServiceCallbacks callbacks);
- void removeSubscription(String uri, in IBinder token, IMediaBrowserServiceCallbacks callbacks);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
deleted file mode 100644
index 8dc480d..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2014 Google Inc. All Rights Reserved.
-
-package android.service.media;
-
-import android.graphics.Bitmap;
-import android.media.MediaParceledListSlice;
-import android.media.session.MediaSession;
-import android.os.Bundle;
-
-/**
- * Media API allows clients to browse through hierarchy of a user’s media collection,
- * playback a specific media entry and interact with the now playing queue.
- * @hide
- */
-oneway interface IMediaBrowserServiceCallbacks {
- /**
- * Invoked when the connected has been established.
- * @param root The root media id for browsing.
- * @param session The {@link MediaSession.Token media session token} that can be used to control
- * the playback of the media app.
- * @param extra Extras returned by the media service.
- */
- void onConnect(String root, in MediaSession.Token session, in Bundle extras);
- void onConnectFailed();
- void onLoadChildren(String mediaId, in MediaParceledListSlice list);
- void onLoadChildrenWithOptions(String mediaId, in MediaParceledListSlice list,
- in Bundle options);
-}
diff --git a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java b/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
deleted file mode 100644
index 76c99b9..0000000
--- a/packages/MediaComponents/apex/java/android/service/media/MediaBrowserService.java
+++ /dev/null
@@ -1,856 +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.service.media;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.UnsupportedAppUsage;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.media.MediaParceledListSlice;
-import android.media.browse.MediaBrowser;
-import android.media.browse.MediaBrowserUtils;
-import android.media.session.MediaSession;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.media.session.MediaSessionManager;
-import android.media.session.MediaSessionManager.RemoteUserInfo;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.service.media.IMediaBrowserService;
-import android.service.media.IMediaBrowserServiceCallbacks;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.Pair;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for media browser services.
- * <p>
- * Media browser services enable applications to browse media content provided by an application
- * and ask the application to start playing it. They may also be used to control content that
- * is already playing by way of a {@link MediaSession}.
- * </p>
- *
- * To extend this class, you must declare the service in your manifest file with
- * an intent filter with the {@link #SERVICE_INTERFACE} action.
- *
- * For example:
- * </p><pre>
- * <service android:name=".MyMediaBrowserService"
- * android:label="@string/service_name" >
- * <intent-filter>
- * <action android:name="android.media.browse.MediaBrowserService" />
- * </intent-filter>
- * </service>
- * </pre>
- *
- */
-public abstract class MediaBrowserService extends Service {
- private static final String TAG = "MediaBrowserService";
- private static final boolean DBG = false;
-
- /**
- * The {@link Intent} that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
-
- /**
- * A key for passing the MediaItem to the ResultReceiver in getItem.
- * @hide
- */
- @UnsupportedAppUsage
- public static final String KEY_MEDIA_ITEM = "media_item";
-
- private static final int RESULT_FLAG_OPTION_NOT_HANDLED = 1 << 0;
- private static final int RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED = 1 << 1;
-
- private static final int RESULT_ERROR = -1;
- private static final int RESULT_OK = 0;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag=true, value = { RESULT_FLAG_OPTION_NOT_HANDLED,
- RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED })
- private @interface ResultFlags { }
-
- private final ArrayMap<IBinder, ConnectionRecord> mConnections = new ArrayMap<>();
- private ConnectionRecord mCurConnection;
- private final Handler mHandler = new Handler();
- private ServiceBinder mBinder;
- MediaSession.Token mSession;
-
- /**
- * All the info about a connection.
- */
- private class ConnectionRecord implements IBinder.DeathRecipient {
- String pkg;
- int uid;
- int pid;
- Bundle rootHints;
- IMediaBrowserServiceCallbacks callbacks;
- BrowserRoot root;
- HashMap<String, List<Pair<IBinder, Bundle>>> subscriptions = new HashMap<>();
-
- @Override
- public void binderDied() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mConnections.remove(callbacks.asBinder());
- }
- });
- }
- }
-
- /**
- * Completion handler for asynchronous callback methods in {@link MediaBrowserService}.
- * <p>
- * Each of the methods that takes one of these to send the result must call
- * {@link #sendResult} to respond to the caller with the given results. If those
- * functions return without calling {@link #sendResult}, they must instead call
- * {@link #detach} before returning, and then may call {@link #sendResult} when
- * they are done. If more than one of those methods is called, an exception will
- * be thrown.
- *
- * @see #onLoadChildren
- * @see #onLoadItem
- */
- public class Result<T> {
- private Object mDebug;
- private boolean mDetachCalled;
- private boolean mSendResultCalled;
- @UnsupportedAppUsage
- private int mFlags;
-
- Result(Object debug) {
- mDebug = debug;
- }
-
- /**
- * Send the result back to the caller.
- */
- public void sendResult(T result) {
- if (mSendResultCalled) {
- throw new IllegalStateException("sendResult() called twice for: " + mDebug);
- }
- mSendResultCalled = true;
- onResultSent(result, mFlags);
- }
-
- /**
- * Detach this message from the current thread and allow the {@link #sendResult}
- * call to happen later.
- */
- public void detach() {
- if (mDetachCalled) {
- throw new IllegalStateException("detach() called when detach() had already"
- + " been called for: " + mDebug);
- }
- if (mSendResultCalled) {
- throw new IllegalStateException("detach() called when sendResult() had already"
- + " been called for: " + mDebug);
- }
- mDetachCalled = true;
- }
-
- boolean isDone() {
- return mDetachCalled || mSendResultCalled;
- }
-
- void setFlags(@ResultFlags int flags) {
- mFlags = flags;
- }
-
- /**
- * Called when the result is sent, after assertions about not being called twice
- * have happened.
- */
- void onResultSent(T result, @ResultFlags int flags) {
- }
- }
-
- private class ServiceBinder extends IMediaBrowserService.Stub {
- @Override
- public void connect(final String pkg, final Bundle rootHints,
- final IMediaBrowserServiceCallbacks callbacks) {
-
- final int pid = Binder.getCallingPid();
- final int uid = Binder.getCallingUid();
- if (!isValidPackage(pkg, uid)) {
- throw new IllegalArgumentException("Package/uid mismatch: uid=" + uid
- + " package=" + pkg);
- }
-
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Clear out the old subscriptions. We are getting new ones.
- mConnections.remove(b);
-
- final ConnectionRecord connection = new ConnectionRecord();
- connection.pkg = pkg;
- connection.pid = pid;
- connection.uid = uid;
- connection.rootHints = rootHints;
- connection.callbacks = callbacks;
-
- mCurConnection = connection;
- connection.root = MediaBrowserService.this.onGetRoot(pkg, uid, rootHints);
- mCurConnection = null;
-
- // If they didn't return something, don't allow this client.
- if (connection.root == null) {
- Log.i(TAG, "No root for client " + pkg + " from service "
- + getClass().getName());
- try {
- callbacks.onConnectFailed();
- } catch (RemoteException ex) {
- Log.w(TAG, "Calling onConnectFailed() failed. Ignoring. "
- + "pkg=" + pkg);
- }
- } else {
- try {
- mConnections.put(b, connection);
- b.linkToDeath(connection, 0);
- if (mSession != null) {
- callbacks.onConnect(connection.root.getRootId(),
- mSession, connection.root.getExtras());
- }
- } catch (RemoteException ex) {
- Log.w(TAG, "Calling onConnect() failed. Dropping client. "
- + "pkg=" + pkg);
- mConnections.remove(b);
- }
- }
- }
- });
- }
-
- @Override
- public void disconnect(final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Clear out the old subscriptions. We are getting new ones.
- final ConnectionRecord old = mConnections.remove(b);
- if (old != null) {
- // TODO
- old.callbacks.asBinder().unlinkToDeath(old, 0);
- }
- }
- });
- }
-
- @Override
- public void addSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
- // do-nothing
- }
-
- @Override
- public void addSubscription(final String id, final IBinder token, final Bundle options,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- // Get the record for the connection
- final ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "addSubscription for callback that isn't registered id="
- + id);
- return;
- }
-
- MediaBrowserService.this.addSubscription(id, connection, token, options);
- }
- });
- }
-
- @Override
- public void removeSubscriptionDeprecated(String id, IMediaBrowserServiceCallbacks callbacks) {
- // do-nothing
- }
-
- @Override
- public void removeSubscription(final String id, final IBinder token,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
-
- ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "removeSubscription for callback that isn't registered id="
- + id);
- return;
- }
- if (!MediaBrowserService.this.removeSubscription(id, connection, token)) {
- Log.w(TAG, "removeSubscription called for " + id
- + " which is not subscribed");
- }
- }
- });
- }
-
- @Override
- public void getMediaItem(final String mediaId, final ResultReceiver receiver,
- final IMediaBrowserServiceCallbacks callbacks) {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- final IBinder b = callbacks.asBinder();
- ConnectionRecord connection = mConnections.get(b);
- if (connection == null) {
- Log.w(TAG, "getMediaItem for callback that isn't registered id=" + mediaId);
- return;
- }
- performLoadItem(mediaId, connection, receiver);
- }
- });
- }
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- mBinder = new ServiceBinder();
- }
-
- @Override
- public IBinder onBind(Intent intent) {
- if (SERVICE_INTERFACE.equals(intent.getAction())) {
- return mBinder;
- }
- return null;
- }
-
- @Override
- public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- }
-
- /**
- * Called to get the root information for browsing by a particular client.
- * <p>
- * The implementation should verify that the client package has permission
- * to access browse media information before returning the root id; it
- * should return null if the client is not allowed to access this
- * information.
- * </p>
- *
- * @param clientPackageName The package name of the application which is
- * requesting access to browse media.
- * @param clientUid The uid of the application which is requesting access to
- * browse media.
- * @param rootHints An optional bundle of service-specific arguments to send
- * to the media browser service when connecting and retrieving the
- * root id for browsing, or null if none. The contents of this
- * bundle may affect the information returned when browsing.
- * @return The {@link BrowserRoot} for accessing this app's content or null.
- * @see BrowserRoot#EXTRA_RECENT
- * @see BrowserRoot#EXTRA_OFFLINE
- * @see BrowserRoot#EXTRA_SUGGESTED
- */
- public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
- int clientUid, @Nullable Bundle rootHints);
-
- /**
- * Called to get information about the children of a media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}
- * with the list of children. If loading the children will be an expensive
- * operation that should be performed on another thread,
- * {@link Result#detach result.detach} may be called before returning from
- * this function, and then {@link Result#sendResult result.sendResult}
- * called when the loading is complete.
- * </p><p>
- * In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list. When the given {@code parentId} is invalid, implementations must
- * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
- * {@link MediaBrowser.SubscriptionCallback#onError}.
- * </p>
- *
- * @param parentId The id of the parent media item whose children are to be
- * queried.
- * @param result The Result to send the list of children to.
- */
- public abstract void onLoadChildren(@NonNull String parentId,
- @NonNull Result<List<MediaBrowser.MediaItem>> result);
-
- /**
- * Called to get information about the children of a media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}
- * with the list of children. If loading the children will be an expensive
- * operation that should be performed on another thread,
- * {@link Result#detach result.detach} may be called before returning from
- * this function, and then {@link Result#sendResult result.sendResult}
- * called when the loading is complete.
- * </p><p>
- * In case the media item does not have any children, call {@link Result#sendResult}
- * with an empty list. When the given {@code parentId} is invalid, implementations must
- * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
- * {@link MediaBrowser.SubscriptionCallback#onError}.
- * </p>
- *
- * @param parentId The id of the parent media item whose children are to be
- * queried.
- * @param result The Result to send the list of children to.
- * @param options The bundle of service-specific arguments sent from the media
- * browser. The information returned through the result should be
- * affected by the contents of this bundle.
- */
- public void onLoadChildren(@NonNull String parentId,
- @NonNull Result<List<MediaBrowser.MediaItem>> result, @NonNull Bundle options) {
- // To support backward compatibility, when the implementation of MediaBrowserService doesn't
- // override onLoadChildren() with options, onLoadChildren() without options will be used
- // instead, and the options will be applied in the implementation of result.onResultSent().
- result.setFlags(RESULT_FLAG_OPTION_NOT_HANDLED);
- onLoadChildren(parentId, result);
- }
-
- /**
- * Called to get information about a specific media item.
- * <p>
- * Implementations must call {@link Result#sendResult result.sendResult}. If
- * loading the item will be an expensive operation {@link Result#detach
- * result.detach} may be called before returning from this function, and
- * then {@link Result#sendResult result.sendResult} called when the item has
- * been loaded.
- * </p><p>
- * When the given {@code itemId} is invalid, implementations must call
- * {@link Result#sendResult result.sendResult} with {@code null}.
- * </p><p>
- * The default implementation will invoke {@link MediaBrowser.ItemCallback#onError}.
- * </p>
- *
- * @param itemId The id for the specific
- * {@link android.media.browse.MediaBrowser.MediaItem}.
- * @param result The Result to send the item to.
- */
- public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
- result.setFlags(RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED);
- result.sendResult(null);
- }
-
- /**
- * Call to set the media session.
- * <p>
- * This should be called as soon as possible during the service's startup.
- * It may only be called once.
- *
- * @param token The token for the service's {@link MediaSession}.
- */
- public void setSessionToken(final MediaSession.Token token) {
- if (token == null) {
- throw new IllegalArgumentException("Session token may not be null.");
- }
- if (mSession != null) {
- throw new IllegalStateException("The session token has already been set.");
- }
- mSession = token;
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- Iterator<ConnectionRecord> iter = mConnections.values().iterator();
- while (iter.hasNext()){
- ConnectionRecord connection = iter.next();
- try {
- connection.callbacks.onConnect(connection.root.getRootId(), token,
- connection.root.getExtras());
- } catch (RemoteException e) {
- Log.w(TAG, "Connection for " + connection.pkg + " is no longer valid.");
- iter.remove();
- }
- }
- }
- });
- }
-
- /**
- * Gets the session token, or null if it has not yet been created
- * or if it has been destroyed.
- */
- public @Nullable MediaSession.Token getSessionToken() {
- return mSession;
- }
-
- /**
- * Gets the root hints sent from the currently connected {@link MediaBrowser}.
- * The root hints are service-specific arguments included in an optional bundle sent to the
- * media browser service when connecting and retrieving the root id for browsing, or null if
- * none. The contents of this bundle may affect the information returned when browsing.
- *
- * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
- * {@link #onLoadChildren} or {@link #onLoadItem}.
- * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
- * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
- * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
- */
- public final Bundle getBrowserRootHints() {
- if (mCurConnection == null) {
- throw new IllegalStateException("This should be called inside of onGetRoot or"
- + " onLoadChildren or onLoadItem methods");
- }
- return mCurConnection.rootHints == null ? null : new Bundle(mCurConnection.rootHints);
- }
-
- /**
- * Gets the browser information who sent the current request.
- *
- * @throws IllegalStateException If this method is called outside of {@link #onGetRoot} or
- * {@link #onLoadChildren} or {@link #onLoadItem}.
- * @see MediaSessionManager#isTrustedForMediaControl(RemoteUserInfo)
- */
- public final RemoteUserInfo getCurrentBrowserInfo() {
- if (mCurConnection == null) {
- throw new IllegalStateException("This should be called inside of onGetRoot or"
- + " onLoadChildren or onLoadItem methods");
- }
- return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
- }
-
- /**
- * Notifies all connected media browsers that the children of
- * the specified parent id have changed in some way.
- * This will cause browsers to fetch subscribed content again.
- *
- * @param parentId The id of the parent media item whose
- * children changed.
- */
- public void notifyChildrenChanged(@NonNull String parentId) {
- notifyChildrenChangedInternal(parentId, null);
- }
-
- /**
- * Notifies all connected media browsers that the children of
- * the specified parent id have changed in some way.
- * This will cause browsers to fetch subscribed content again.
- *
- * @param parentId The id of the parent media item whose
- * children changed.
- * @param options The bundle of service-specific arguments to send
- * to the media browser. The contents of this bundle may
- * contain the information about the change.
- */
- public void notifyChildrenChanged(@NonNull String parentId, @NonNull Bundle options) {
- if (options == null) {
- throw new IllegalArgumentException("options cannot be null in notifyChildrenChanged");
- }
- notifyChildrenChangedInternal(parentId, options);
- }
-
- private void notifyChildrenChangedInternal(final String parentId, final Bundle options) {
- if (parentId == null) {
- throw new IllegalArgumentException("parentId cannot be null in notifyChildrenChanged");
- }
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- for (IBinder binder : mConnections.keySet()) {
- ConnectionRecord connection = mConnections.get(binder);
- List<Pair<IBinder, Bundle>> callbackList =
- connection.subscriptions.get(parentId);
- if (callbackList != null) {
- for (Pair<IBinder, Bundle> callback : callbackList) {
- if (MediaBrowserUtils.hasDuplicatedItems(options, callback.second)) {
- performLoadChildren(parentId, connection, callback.second);
- }
- }
- }
- }
- }
- });
- }
-
- /**
- * Return whether the given package is one of the ones that is owned by the uid.
- */
- private boolean isValidPackage(String pkg, int uid) {
- if (pkg == null) {
- return false;
- }
- final PackageManager pm = getPackageManager();
- final String[] packages = pm.getPackagesForUid(uid);
- final int N = packages.length;
- for (int i=0; i<N; i++) {
- if (packages[i].equals(pkg)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Save the subscription and if it is a new subscription send the results.
- */
- private void addSubscription(String id, ConnectionRecord connection, IBinder token,
- Bundle options) {
- // Save the subscription
- List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
- if (callbackList == null) {
- callbackList = new ArrayList<>();
- }
- for (Pair<IBinder, Bundle> callback : callbackList) {
- if (token == callback.first
- && MediaBrowserUtils.areSameOptions(options, callback.second)) {
- return;
- }
- }
- callbackList.add(new Pair<>(token, options));
- connection.subscriptions.put(id, callbackList);
- // send the results
- performLoadChildren(id, connection, options);
- }
-
- /**
- * Remove the subscription.
- */
- private boolean removeSubscription(String id, ConnectionRecord connection, IBinder token) {
- if (token == null) {
- return connection.subscriptions.remove(id) != null;
- }
- boolean removed = false;
- List<Pair<IBinder, Bundle>> callbackList = connection.subscriptions.get(id);
- if (callbackList != null) {
- Iterator<Pair<IBinder, Bundle>> iter = callbackList.iterator();
- while (iter.hasNext()){
- if (token == iter.next().first) {
- removed = true;
- iter.remove();
- }
- }
- if (callbackList.size() == 0) {
- connection.subscriptions.remove(id);
- }
- }
- return removed;
- }
-
- /**
- * Call onLoadChildren and then send the results back to the connection.
- * <p>
- * Callers must make sure that this connection is still connected.
- */
- private void performLoadChildren(final String parentId, final ConnectionRecord connection,
- final Bundle options) {
- final Result<List<MediaBrowser.MediaItem>> result
- = new Result<List<MediaBrowser.MediaItem>>(parentId) {
- @Override
- void onResultSent(List<MediaBrowser.MediaItem> list, @ResultFlags int flag) {
- if (mConnections.get(connection.callbacks.asBinder()) != connection) {
- if (DBG) {
- Log.d(TAG, "Not sending onLoadChildren result for connection that has"
- + " been disconnected. pkg=" + connection.pkg + " id=" + parentId);
- }
- return;
- }
-
- List<MediaBrowser.MediaItem> filteredList =
- (flag & RESULT_FLAG_OPTION_NOT_HANDLED) != 0
- ? applyOptions(list, options) : list;
- final MediaParceledListSlice<MediaBrowser.MediaItem> pls =
- filteredList == null ? null : new MediaParceledListSlice<>(filteredList);
- try {
- connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
- } catch (RemoteException ex) {
- // The other side is in the process of crashing.
- Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
- + " package=" + connection.pkg);
- }
- }
- };
-
- mCurConnection = connection;
- if (options == null) {
- onLoadChildren(parentId, result);
- } else {
- onLoadChildren(parentId, result, options);
- }
- mCurConnection = null;
-
- if (!result.isDone()) {
- throw new IllegalStateException("onLoadChildren must call detach() or sendResult()"
- + " before returning for package=" + connection.pkg + " id=" + parentId);
- }
- }
-
- private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
- final Bundle options) {
- if (list == null) {
- return null;
- }
- int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
- int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
- if (page == -1 && pageSize == -1) {
- return list;
- }
- int fromIndex = pageSize * page;
- int toIndex = fromIndex + pageSize;
- if (page < 0 || pageSize < 1 || fromIndex >= list.size()) {
- return Collections.EMPTY_LIST;
- }
- if (toIndex > list.size()) {
- toIndex = list.size();
- }
- return list.subList(fromIndex, toIndex);
- }
-
- private void performLoadItem(String itemId, final ConnectionRecord connection,
- final ResultReceiver receiver) {
- final Result<MediaBrowser.MediaItem> result =
- new Result<MediaBrowser.MediaItem>(itemId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item, @ResultFlags int flag) {
- if (mConnections.get(connection.callbacks.asBinder()) != connection) {
- if (DBG) {
- Log.d(TAG, "Not sending onLoadItem result for connection that has"
- + " been disconnected. pkg=" + connection.pkg + " id=" + itemId);
- }
- return;
- }
- if ((flag & RESULT_FLAG_ON_LOAD_ITEM_NOT_IMPLEMENTED) != 0) {
- receiver.send(RESULT_ERROR, null);
- return;
- }
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(RESULT_OK, bundle);
- }
- };
-
- mCurConnection = connection;
- onLoadItem(itemId, result);
- mCurConnection = null;
-
- if (!result.isDone()) {
- throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
- + " before returning for id=" + itemId);
- }
- }
-
- /**
- * Contains information that the browser service needs to send to the client
- * when first connected.
- */
- public static final class BrowserRoot {
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for recently played media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving media items that are recently played.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_OFFLINE
- * @see #EXTRA_SUGGESTED
- */
- public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
-
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for offline media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving media items that are can be played without an
- * internet connection.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_RECENT
- * @see #EXTRA_SUGGESTED
- */
- public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
-
- /**
- * The lookup key for a boolean that indicates whether the browser service should return a
- * browser root for suggested media items.
- *
- * <p>When creating a media browser for a given media browser service, this key can be
- * supplied as a root hint for retrieving the media items suggested by the media browser
- * service. The list of media items passed in {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
- * is considered ordered by relevance, first being the top suggestion.
- * If the media browser service can provide such media items, the implementation must return
- * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
- *
- * <p>The root hint may contain multiple keys.
- *
- * @see #EXTRA_RECENT
- * @see #EXTRA_OFFLINE
- */
- public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-
- final private String mRootId;
- final private Bundle mExtras;
-
- /**
- * Constructs a browser root.
- * @param rootId The root id for browsing.
- * @param extras Any extras about the browser service.
- */
- public BrowserRoot(@NonNull String rootId, @Nullable Bundle extras) {
- if (rootId == null) {
- throw new IllegalArgumentException("The root id in BrowserRoot cannot be null. " +
- "Use null for BrowserRoot instead.");
- }
- mRootId = rootId;
- mExtras = extras;
- }
-
- /**
- * Gets the root id for browsing.
- */
- public String getRootId() {
- return mRootId;
- }
-
- /**
- * Gets any extras about the browser service.
- */
- public Bundle getExtras() {
- return mExtras;
- }
- }
-}
diff --git a/packages/OWNERS b/packages/OWNERS
deleted file mode 100644
index 3b9fd2b..0000000
--- a/packages/OWNERS
+++ /dev/null
@@ -1,9 +0,0 @@
-akersten@google.com
-dwkang@google.com
-hdmoon@google.com
-insun@google.com
-jaewan@google.com
-jinpark@google.com
-marcone@google.com
-sungsoo@google.com
-wjia@google.com