java.lang.Object
↳androidx.media2.session.MediaUtils
Gradle dependencies
compile group: 'androidx.media2', name: 'media2-session', version: '1.3.0'
- groupId: androidx.media2
- artifactId: media2-session
- version: 1.3.0
Artifact androidx.media2:media2-session:1.3.0 it located at Google repository (https://maven.google.com/)
Summary
Methods |
---|
public static java.util.List<ParcelImpl> | convertCommandButtonListToParcelImplList(java.util.List<MediaSession.CommandButton> commandButtonList)
Convert a list of MediaSession.CommandButton to a list of ParcelImpl. |
public static java.util.List<MediaItem> | convertMediaItemListToMediaItemList(java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> items)
Convert a list of to a list of MediaItem. |
public static ParcelImplListSlice | convertMediaItemListToParcelImplListSlice(java.util.List<MediaItem> mediaItemList)
Convert a list of MediaItem to a list of ParcelImplListSlice. |
public static java.util.List<MediaItem> | convertParcelImplListSliceToMediaItemList(ParcelImplListSlice listSlice)
Convert a ParcelImplListSlice to a list of MediaItem. |
public static java.util.List<MediaItem> | convertQueueItemListToMediaItemList(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> items)
Convert a list of android.support.v4.media.session.MediaSessionCompat.QueueItem to a list of MediaItem. |
public static java.util.List<MediaSession.CommandButton> | convertToCustomLayout(android.support.v4.media.session.PlaybackStateCompat state)
Converts android.support.v4.media.session.PlaybackStateCompat.CustomAction in the android.support.v4.media.session.PlaybackStateCompat to the custom layout which
is the list of the MediaSession.CommandButton. |
public static MediaLibraryService.LibraryParams | convertToLibraryParams(Context context, Bundle legacyBundle)
Converts the rootHints, option, and extra to the MediaLibraryService.LibraryParams. |
public static MediaItem | convertToMediaItem(android.support.v4.media.MediaBrowserCompat.MediaItem item)
Creates a MediaItem from the . |
public static MediaItem | convertToMediaItem(android.support.v4.media.MediaDescriptionCompat descriptionCompat)
Convert a android.support.v4.media.MediaDescriptionCompat to a MediaItem. |
public static android.support.v4.media.MediaBrowserCompat.MediaItem | convertToMediaItem(MediaItem item2)
Creates a from the MediaItem. |
public static MediaItem | convertToMediaItem(android.support.v4.media.MediaMetadataCompat metadataCompat, int ratingType)
Convert a android.support.v4.media.MediaMetadataCompat from the getMetadata
and rating type to a MediaItem. |
public static MediaItem | convertToMediaItem(android.support.v4.media.session.MediaSessionCompat.QueueItem item)
Convert a android.support.v4.media.session.MediaSessionCompat.QueueItem to a MediaItem. |
public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> | convertToMediaItemList(java.util.List<MediaItem> items)
Convert a list of MediaItem to a list of . |
public static MediaMetadata | convertToMediaMetadata(java.lang.CharSequence queueTitle)
Creates a MediaMetadata from the java.lang.CharSequence . |
public static android.support.v4.media.MediaMetadataCompat | convertToMediaMetadataCompat(MediaMetadata metadata)
Creates a android.support.v4.media.MediaMetadataCompat from the MediaMetadata. |
public static int | convertToPlaybackStateCompatState(int playerState, int bufferingState)
Convert a and
into . |
public static int | convertToPlayerState(android.support.v4.media.session.PlaybackStateCompat state)
Convert a android.support.v4.media.session.PlaybackStateCompat into . |
public static long | convertToQueueItemId(int mediaItemIndex)
Convert the index of a MediaItem in a playlist into id of android.support.v4.media.session.MediaSessionCompat.QueueItem . |
public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> | convertToQueueItemList(java.util.List<MediaItem> items)
Convert a list of MediaItem to a list of android.support.v4.media.session.MediaSessionCompat.QueueItem . |
public static Rating | convertToRating(android.support.v4.media.RatingCompat ratingCompat)
Creates a Rating from the android.support.v4.media.RatingCompat . |
public static android.support.v4.media.RatingCompat | convertToRatingCompat(Rating rating)
Creates a android.support.v4.media.RatingCompat from the Rating. |
public static Bundle | convertToRootHints(MediaLibraryService.LibraryParams params)
Converts MediaLibraryService.LibraryParams to the root hints. |
public static SessionCommandGroup | convertToSessionCommandGroup(long sessionFlags, android.support.v4.media.session.PlaybackStateCompat state)
Converts session flags and
android.support.v4.media.session.PlaybackStateCompat to the SessionCommandGroup. |
public static android.support.v4.media.MediaDescriptionCompat | createMediaDescriptionCompat(java.lang.String mediaId)
Creates android.support.v4.media.MediaDescriptionCompat with the id |
public static int | getLegacyStreamType(AudioAttributesCompat attrs)
Gets the legacy stream type from AudioAttributesCompat. |
public static boolean | isUnparcelableBundle(Bundle bundle)
Returns whether the bundle is not parcelable. |
public static void | keepUnparcelableBundlesOnly(java.util.List<Bundle> bundles)
Removes unparcelable bundles in the given list. |
public static java.util.List<java.lang.Object> | removeNullElements(java.util.List<java.lang.Object> list)
Removes all null elements from the list and returns it. |
public static int | toBufferingState(int playbackStateCompatState)
Convert a into . |
public static MediaController.PlaybackInfo | toPlaybackInfo2(android.support.v4.media.session.MediaControllerCompat.PlaybackInfo info)
Convert a into
MediaController.PlaybackInfo. |
public static java.util.List<Parcelable> | truncateListBySize(java.util.List<Parcelable> list, int sizeLimitInBytes)
Return a list which consists of first N items of the given list with the same order. |
public static java.util.List<SessionPlayer.TrackInfo> | upcastForPreparceling(java.util.List<SessionPlayer.TrackInfo> tracks)
Upcasts a list of SessionPlayer.TrackInfo subclass objects to a List of SessionPlayer.TrackInfo type
for pre-parceling. |
public static MediaItem | upcastForPreparceling(MediaItem item)
Upcasts a MediaItem to the MediaItem type for pre-parceling. |
public static SessionPlayer.TrackInfo | upcastForPreparceling(SessionPlayer.TrackInfo track)
Upcasts a SessionPlayer.TrackInfo subclass to the SessionPlayer.TrackInfo type for pre-parceling. |
public static VideoSize | upcastForPreparceling(VideoSize size)
Upcasts a VideoSize subclass to the MediaItem type for pre-parceling. |
from java.lang.Object | clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
Fields
public static final java.lang.String
TAGpublic static final int
TRANSACTION_SIZE_LIMIT_IN_BYTESpublic static final java.util.concurrent.Executor
DIRECT_EXECUTORpublic static final int
VERSION_UNKNOWNpublic static final int
VERSION_0public static final int
CURRENT_VERSIONMethods
Upcasts a MediaItem to the MediaItem type for pre-parceling. Note that
MediaItem's subclass object cannot be parceled due to the security issue.
Parameters:
item: an item
Returns:
upcasted item
Upcasts a VideoSize subclass to the MediaItem type for pre-parceling.
Note that VideoSize's subclass object cannot be parceled due the issue that remote
apps may not have the subclass.
Parameters:
size: a size
Returns:
upcasted size
Upcasts a SessionPlayer.TrackInfo subclass to the SessionPlayer.TrackInfo type for pre-parceling.
Note that SessionPlayer.TrackInfo's subclass object cannot be parceled due to the issue that remote
apps may not have the subclass.
Parameters:
track: a track
Returns:
upcasted track
public static java.util.List<SessionPlayer.TrackInfo>
upcastForPreparceling(java.util.List<SessionPlayer.TrackInfo> tracks)
Upcasts a list of SessionPlayer.TrackInfo subclass objects to a List of SessionPlayer.TrackInfo type
for pre-parceling. Note that SessionPlayer.TrackInfo's subclass object cannot be parceled due
to the issue that remote apps may not have the subclass.
Parameters:
tracks: a list of tracks
Returns:
list of upcasted tracks
public static android.support.v4.media.MediaBrowserCompat.MediaItem
convertToMediaItem(
MediaItem item2)
Creates a from the MediaItem.
Parameters:
item2: an item.
Returns:
The newly created media item.
public static java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem>
convertToMediaItemList(java.util.List<MediaItem> items)
Convert a list of MediaItem to a list of .
public static
MediaItem convertToMediaItem(android.support.v4.media.MediaBrowserCompat.MediaItem item)
Creates a MediaItem from the .
Parameters:
item: an item.
Returns:
The newly created media item.
public static
MediaItem convertToMediaItem(android.support.v4.media.session.MediaSessionCompat.QueueItem item)
Convert a android.support.v4.media.session.MediaSessionCompat.QueueItem
to a MediaItem.
public static
MediaItem convertToMediaItem(android.support.v4.media.MediaMetadataCompat metadataCompat, int ratingType)
Convert a android.support.v4.media.MediaMetadataCompat
from the getMetadata
and rating type to a MediaItem.
public static
MediaItem convertToMediaItem(android.support.v4.media.MediaDescriptionCompat descriptionCompat)
Convert a android.support.v4.media.MediaDescriptionCompat
to a MediaItem.
public static java.util.List<MediaItem>
convertMediaItemListToMediaItemList(java.util.List<android.support.v4.media.MediaBrowserCompat.MediaItem> items)
Convert a list of to a list of MediaItem.
public static java.util.List<MediaItem>
convertQueueItemListToMediaItemList(java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem> items)
Convert a list of android.support.v4.media.session.MediaSessionCompat.QueueItem
to a list of MediaItem.
public static android.support.v4.media.MediaDescriptionCompat
createMediaDescriptionCompat(java.lang.String mediaId)
Creates android.support.v4.media.MediaDescriptionCompat
with the id
public static java.util.List<android.support.v4.media.session.MediaSessionCompat.QueueItem>
convertToQueueItemList(java.util.List<MediaItem> items)
Convert a list of MediaItem to a list of android.support.v4.media.session.MediaSessionCompat.QueueItem
. The index of the item
would be used as the queue ID to match the behavior of MediaController.
public static long
convertToQueueItemId(int mediaItemIndex)
Convert the index of a MediaItem in a playlist into id of android.support.v4.media.session.MediaSessionCompat.QueueItem
.
Parameters:
mediaItemIndex: index of a MediaItem in a playlist. It can be
SessionPlayer.INVALID_ITEM_INDEX.
Returns:
id of android.support.v4.media.session.MediaSessionCompat.QueueItem
or UNKNOWN_ID
if the index is
SessionPlayer.INVALID_ITEM_INDEX.
public static java.util.List<MediaItem>
convertParcelImplListSliceToMediaItemList(
ParcelImplListSlice listSlice)
Convert a ParcelImplListSlice to a list of MediaItem.
public static java.util.List<Parcelable>
truncateListBySize(java.util.List<Parcelable> list, int sizeLimitInBytes)
Return a list which consists of first N items of the given list with the same order.
N is determined as the maximum number of items whose total parcelled size is less
than sizeLimitInBytes.
public static
MediaMetadata convertToMediaMetadata(java.lang.CharSequence queueTitle)
Creates a MediaMetadata from the java.lang.CharSequence
.
public static android.support.v4.media.MediaMetadataCompat
convertToMediaMetadataCompat(
MediaMetadata metadata)
Creates a android.support.v4.media.MediaMetadataCompat
from the MediaMetadata.
Parameters:
metadata: A MediaMetadata object.
Returns:
The newly created android.support.v4.media.MediaMetadataCompat
object.
public static
Rating convertToRating(android.support.v4.media.RatingCompat ratingCompat)
Creates a Rating from the android.support.v4.media.RatingCompat
.
Parameters:
ratingCompat: A android.support.v4.media.RatingCompat
object.
Returns:
The newly created Rating object.
public static android.support.v4.media.RatingCompat
convertToRatingCompat(
Rating rating)
Creates a android.support.v4.media.RatingCompat
from the Rating.
Parameters:
rating: A Rating object.
Returns:
The newly created android.support.v4.media.RatingCompat
object.
public static java.util.List<ParcelImpl>
convertCommandButtonListToParcelImplList(java.util.List<MediaSession.CommandButton> commandButtonList)
Convert a list of MediaSession.CommandButton to a list of ParcelImpl.
public static
ParcelImplListSlice convertMediaItemListToParcelImplListSlice(java.util.List<MediaItem> mediaItemList)
Convert a list of MediaItem to a list of ParcelImplListSlice.
public static int
convertToPlaybackStateCompatState(int playerState, int bufferingState)
Convert a and
into .
public static int
convertToPlayerState(android.support.v4.media.session.PlaybackStateCompat state)
Convert a android.support.v4.media.session.PlaybackStateCompat
into .
public static int
toBufferingState(int playbackStateCompatState)
Convert a into .
Convert a into
MediaController.PlaybackInfo.
public static boolean
isUnparcelableBundle(Bundle bundle)
Returns whether the bundle is not parcelable.
public static void
keepUnparcelableBundlesOnly(java.util.List<Bundle> bundles)
Removes unparcelable bundles in the given list.
Converts the rootHints, option, and extra to the MediaLibraryService.LibraryParams.
Parameters:
legacyBundle:
Returns:
new LibraryParams
Converts MediaLibraryService.LibraryParams to the root hints.
Parameters:
params:
Returns:
new root hints
public static java.util.List<java.lang.Object>
removeNullElements(java.util.List<java.lang.Object> list)
Removes all null elements from the list and returns it.
Parameters:
list:
Returns:
public static
SessionCommandGroup convertToSessionCommandGroup(long sessionFlags, android.support.v4.media.session.PlaybackStateCompat state)
Converts session flags
and
android.support.v4.media.session.PlaybackStateCompat
to the SessionCommandGroup.
This ignores actions
in the
android.support.v4.media.session.PlaybackStateCompat
to workaround media apps' issues that they don't set playback
state correctly.
Parameters:
sessionFlags: session flag
state: playback state
Returns:
the converted session command group
public static java.util.List<MediaSession.CommandButton>
convertToCustomLayout(android.support.v4.media.session.PlaybackStateCompat state)
Converts android.support.v4.media.session.PlaybackStateCompat.CustomAction
in the android.support.v4.media.session.PlaybackStateCompat
to the custom layout which
is the list of the MediaSession.CommandButton.
Parameters:
state: playback state
Returns:
custom layout. Always non-null.
Gets the legacy stream type from AudioAttributesCompat.
Parameters:
attrs: audio attributes
Returns:
int legacy stream type from AudioManager
Source
/*
* Copyright 2019 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 androidx.media2.session;
import static android.support.v4.media.MediaDescriptionCompat.EXTRA_BT_FOLDER_TYPE;
import static android.support.v4.media.session.MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import static androidx.media2.common.MediaMetadata.BROWSABLE_TYPE_MIXED;
import static androidx.media2.common.MediaMetadata.BROWSABLE_TYPE_NONE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_ADVERTISEMENT;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_BROWSABLE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DISPLAY_DESCRIPTION;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DISPLAY_ICON;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DISPLAY_TITLE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_DOWNLOAD_STATUS;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_EXTRAS;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_MEDIA_ID;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_MEDIA_URI;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_PLAYABLE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_TITLE;
import static androidx.media2.common.MediaMetadata.METADATA_KEY_USER_RATING;
import static androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_DESELECT_TRACK;
import static androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_SELECT_TRACK;
import static androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_SET_SPEED;
import static androidx.media2.session.SessionCommand.COMMAND_CODE_PLAYER_SET_SURFACE;
import static androidx.media2.session.SessionCommand.COMMAND_VERSION_1;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.media.AudioManager;
import android.net.Uri;
import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.media.MediaBrowserCompat;
import android.support.v4.media.MediaDescriptionCompat;
import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.RatingCompat;
import android.support.v4.media.session.MediaControllerCompat;
import android.support.v4.media.session.MediaSessionCompat.QueueItem;
import android.support.v4.media.session.PlaybackStateCompat;
import android.support.v4.media.session.PlaybackStateCompat.CustomAction;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.media.AudioAttributesCompat;
import androidx.media.MediaBrowserServiceCompat.BrowserRoot;
import androidx.media2.common.MediaItem;
import androidx.media2.common.MediaMetadata;
import androidx.media2.common.MediaParcelUtils;
import androidx.media2.common.ParcelImplListSlice;
import androidx.media2.common.Rating;
import androidx.media2.common.SessionPlayer;
import androidx.media2.common.SessionPlayer.TrackInfo;
import androidx.media2.common.VideoSize;
import androidx.media2.session.MediaLibraryService.LibraryParams;
import androidx.media2.session.MediaSession.CommandButton;
import androidx.versionedparcelable.ParcelImpl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
/**
*/
@RestrictTo(LIBRARY)
public class MediaUtils {
public static final String TAG = "MediaUtils";
public static final int TRANSACTION_SIZE_LIMIT_IN_BYTES = 256 * 1024; // 256KB
// Stub BrowserRoot for accepting any connection here.
public static final BrowserRoot sDefaultBrowserRoot =
new BrowserRoot(MediaLibraryService.SERVICE_INTERFACE, null);
public static final Executor DIRECT_EXECUTOR = new Executor() {
@Override
public void execute(Runnable command) {
command.run();
}
};
// UNKNOWN version for legacy support
public static final int VERSION_UNKNOWN = -1;
// Initial version for all Media2 APIs.
public static final int VERSION_0 = 0;
// Current version for all Media2 APIs.
public static final int CURRENT_VERSION = VERSION_0;
private static final Map<String, String> METADATA_COMPAT_KEY_TO_METADATA_KEY = new HashMap<>();
private static final Map<String, String> METADATA_KEY_TO_METADATA_COMPAT_KEY = new HashMap<>();
static {
METADATA_COMPAT_KEY_TO_METADATA_KEY.put(
MediaMetadataCompat.METADATA_KEY_ADVERTISEMENT, METADATA_KEY_ADVERTISEMENT);
METADATA_COMPAT_KEY_TO_METADATA_KEY.put(MediaMetadataCompat.METADATA_KEY_BT_FOLDER_TYPE,
METADATA_KEY_BROWSABLE);
METADATA_COMPAT_KEY_TO_METADATA_KEY.put(MediaMetadataCompat.METADATA_KEY_DOWNLOAD_STATUS,
METADATA_KEY_DOWNLOAD_STATUS);
// Invert METADATA_COMPAT_KEY_TO_METADATA_KEY to create METADATA_KEY_TO_METADATA_COMPAT_KEY.
for (Map.Entry<String, String> entry : METADATA_COMPAT_KEY_TO_METADATA_KEY.entrySet()) {
if (METADATA_KEY_TO_METADATA_COMPAT_KEY.containsKey(entry.getValue())) {
throw new RuntimeException("Shouldn't map to the same value");
}
METADATA_KEY_TO_METADATA_COMPAT_KEY.put(entry.getValue(), entry.getKey());
}
}
private MediaUtils() {
}
/**
* Upcasts a {@link MediaItem} to the {@link MediaItem} type for pre-parceling. Note that
* {@link MediaItem}'s subclass object cannot be parceled due to the security issue.
*
* @param item an item
* @return upcasted item
*/
@Nullable
public static MediaItem upcastForPreparceling(@Nullable MediaItem item) {
if (item == null || item.getClass() == MediaItem.class) {
return item;
}
return new MediaItem.Builder()
.setStartPosition(item.getStartPosition())
.setEndPosition(item.getEndPosition())
.setMetadata(item.getMetadata()).build();
}
/**
* Upcasts a {@link VideoSize} subclass to the {@link MediaItem} type for pre-parceling.
* Note that {@link VideoSize}'s subclass object cannot be parceled due the issue that remote
* apps may not have the subclass.
*
* @param size a size
* @return upcasted size
*/
@Nullable
public static VideoSize upcastForPreparceling(@Nullable VideoSize size) {
if (size == null || size.getClass() == VideoSize.class) {
return size;
}
return new VideoSize(size.getWidth(), size.getHeight());
}
/**
* Upcasts a {@link TrackInfo} subclass to the {@link TrackInfo} type for pre-parceling.
* Note that {@link TrackInfo}'s subclass object cannot be parceled due to the issue that remote
* apps may not have the subclass.
*
* @param track a track
* @return upcasted track
*/
@Nullable
public static TrackInfo upcastForPreparceling(@Nullable TrackInfo track) {
if (track == null || track.getClass() == TrackInfo.class) {
return track;
}
return new TrackInfo(track.getId(), track.getTrackType(), track.getFormat(),
track.isSelectable());
}
/**
* Upcasts a list of {@link TrackInfo} subclass objects to a List of {@link TrackInfo} type
* for pre-parceling. Note that {@link TrackInfo}'s subclass object cannot be parceled due
* to the issue that remote apps may not have the subclass.
*
* @param tracks a list of tracks
* @return list of upcasted tracks
*/
@Nullable
public static List<TrackInfo> upcastForPreparceling(@Nullable List<TrackInfo> tracks) {
if (tracks == null) {
return tracks;
}
List<TrackInfo> upcastTracks = new ArrayList<>();
for (int i = 0; i < tracks.size(); i++) {
upcastTracks.add(upcastForPreparceling(tracks.get(i)));
}
return upcastTracks;
}
/**
* Creates a {@link MediaBrowserCompat.MediaItem} from the {@link MediaItem}.
*
* @param item2 an item.
* @return The newly created media item.
*/
@Nullable
public static MediaBrowserCompat.MediaItem convertToMediaItem(@Nullable MediaItem item2) {
if (item2 == null) {
return null;
}
int flags = 0;
MediaDescriptionCompat descCompat;
MediaMetadata metadata = item2.getMetadata();
if (metadata == null) {
descCompat = new MediaDescriptionCompat.Builder()
.setMediaId(item2.getMediaId())
.build();
} else {
MediaDescriptionCompat.Builder builder = new MediaDescriptionCompat.Builder()
.setMediaId(item2.getMediaId())
.setSubtitle(metadata.getText(METADATA_KEY_DISPLAY_SUBTITLE))
.setDescription(metadata.getText(METADATA_KEY_DISPLAY_DESCRIPTION))
.setIconBitmap(metadata.getBitmap(METADATA_KEY_DISPLAY_ICON))
.setExtras(metadata.getExtras());
String title = metadata.getString(METADATA_KEY_TITLE);
if (title != null) {
builder.setTitle(title);
} else {
builder.setTitle(metadata.getString(METADATA_KEY_DISPLAY_TITLE));
}
String displayIconUri = metadata.getString(METADATA_KEY_DISPLAY_ICON_URI);
if (displayIconUri != null) {
builder.setIconUri(Uri.parse(displayIconUri));
}
String mediaUri = metadata.getString(METADATA_KEY_MEDIA_URI);
if (mediaUri != null) {
builder.setMediaUri(Uri.parse(mediaUri));
}
descCompat = builder.build();
boolean browsable = metadata.containsKey(METADATA_KEY_BROWSABLE)
&& metadata.getLong(METADATA_KEY_BROWSABLE) != BROWSABLE_TYPE_NONE;
boolean playable = metadata.getLong(METADATA_KEY_PLAYABLE) != 0;
flags = (browsable ? MediaBrowserCompat.MediaItem.FLAG_BROWSABLE : 0)
| (playable ? MediaBrowserCompat.MediaItem.FLAG_PLAYABLE : 0);
}
return new MediaBrowserCompat.MediaItem(descCompat, flags);
}
/**
* Convert a list of {@link MediaItem} to a list of {@link MediaBrowserCompat.MediaItem}.
*/
@Nullable
public static List<MediaBrowserCompat.MediaItem> convertToMediaItemList(
@Nullable List<MediaItem> items) {
if (items == null) {
return null;
}
List<MediaBrowserCompat.MediaItem> result = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
result.add(convertToMediaItem(items.get(i)));
}
return result;
}
/**
* Creates a {@link MediaItem} from the {@link MediaBrowserCompat.MediaItem}.
*
* @param item an item.
* @return The newly created media item.
*/
public static MediaItem convertToMediaItem(MediaBrowserCompat.MediaItem item) {
if (item == null) {
return null;
}
MediaMetadata metadata = convertToMediaMetadata(item.getDescription(),
item.isBrowsable(), item.isPlayable());
return new MediaItem.Builder()
.setMetadata(metadata)
.build();
}
/**
* Convert a {@link QueueItem} to a {@link MediaItem}.
*/
public static MediaItem convertToMediaItem(QueueItem item) {
if (item == null) {
return null;
}
// descriptionCompat cannot be null
MediaDescriptionCompat descriptionCompat = item.getDescription();
MediaMetadata metadata = convertToMediaMetadata(descriptionCompat, false, true);
return new MediaItem.Builder()
.setMetadata(metadata)
.build();
}
/**
* Convert a {@link MediaMetadataCompat} from the {@link MediaControllerCompat#getMetadata()}
* and rating type to a {@link MediaItem}.
*/
@Nullable
@SuppressWarnings("deprecation")
public static MediaItem convertToMediaItem(@Nullable MediaMetadataCompat metadataCompat,
int ratingType) {
if (metadataCompat == null) {
return null;
}
// Item is from the MediaControllerCompat, so forcefully set the playable.
MediaMetadata.Builder builder = new MediaMetadata.Builder()
.putLong(METADATA_KEY_PLAYABLE, 1)
.putRating(METADATA_KEY_USER_RATING,
MediaUtils.convertToRating(RatingCompat.newUnratedRating(ratingType)));
for (String key : metadataCompat.keySet()) {
Object value = metadataCompat.getBundle().get(key);
String metadataKey = METADATA_COMPAT_KEY_TO_METADATA_KEY.containsKey(key)
? METADATA_COMPAT_KEY_TO_METADATA_KEY.get(key) : key;
if (value instanceof CharSequence) {
builder.putText(metadataKey, (CharSequence) value);
} else if (value instanceof Bitmap) {
builder.putBitmap(metadataKey, (Bitmap) value);
} else if (value instanceof Long) {
builder.putLong(metadataKey, (Long) value);
} else if ((value instanceof RatingCompat)
|| (Build.VERSION.SDK_INT >= 19 && value instanceof android.media.Rating)) {
// Must be fwk Rating or RatingCompat according to SDK versions.
// Use MediaMetadataCompat#getRating(key) to get a RatingCompat object.
try {
RatingCompat rating = metadataCompat.getRating(key);
builder.putRating(metadataKey, MediaUtils.convertToRating(rating));
} catch (Exception e) {
// Prevent from CastException in the getRating() due to the future changes.
}
}
}
return new MediaItem.Builder().setMetadata(builder.build()).build();
}
/**
* Convert a {@link MediaDescriptionCompat} to a {@link MediaItem}.
*/
@Nullable
public static MediaItem convertToMediaItem(@Nullable MediaDescriptionCompat descriptionCompat) {
MediaMetadata metadata = convertToMediaMetadata(descriptionCompat, false, true);
if (metadata == null) {
return null;
}
return new MediaItem.Builder().setMetadata(metadata).build();
}
/**
* Convert a list of {@link MediaBrowserCompat.MediaItem} to a list of {@link MediaItem}.
*/
public static List<MediaItem> convertMediaItemListToMediaItemList(
List<MediaBrowserCompat.MediaItem> items) {
if (items == null) {
return null;
}
List<MediaItem> result = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
result.add(convertToMediaItem(items.get(i)));
}
return result;
}
/**
* Convert a list of {@link QueueItem} to a list of {@link MediaItem}.
*/
public static List<MediaItem> convertQueueItemListToMediaItemList(List<QueueItem> items) {
if (items == null) {
return null;
}
List<MediaItem> result = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
MediaItem item = convertToMediaItem(items.get(i));
if (item != null) {
result.add(item);
}
}
return result;
}
/**
* Creates {@link MediaDescriptionCompat} with the id
*/
public static MediaDescriptionCompat createMediaDescriptionCompat(String mediaId) {
if (TextUtils.isEmpty(mediaId)) {
return null;
}
return new MediaDescriptionCompat.Builder().setMediaId(mediaId).build();
}
/**
* Convert a list of {@link MediaItem} to a list of {@link QueueItem}. The index of the item
* would be used as the queue ID to match the behavior of {@link MediaController}.
*/
public static List<QueueItem> convertToQueueItemList(List<MediaItem> items) {
if (items == null) {
return null;
}
List<QueueItem> result = new ArrayList<>();
for (int i = 0; i < items.size(); i++) {
MediaItem item = items.get(i);
MediaDescriptionCompat description = (item.getMetadata() == null)
? new MediaDescriptionCompat.Builder().setMediaId(item.getMediaId()).build()
: convertToMediaMetadataCompat(item.getMetadata()).getDescription();
long id = convertToQueueItemId(i);
result.add(new QueueItem(description, id));
}
return result;
}
/**
* Convert the index of a {@link MediaItem} in a playlist into id of {@link QueueItem}.
*
* @param mediaItemIndex index of a {@link MediaItem} in a playlist. It can be
* {@link SessionPlayer#INVALID_ITEM_INDEX}.
* @return id of {@link QueueItem} or {@link QueueItem#UNKNOWN_ID} if the index is
* {@link SessionPlayer#INVALID_ITEM_INDEX}.
*/
public static long convertToQueueItemId(int mediaItemIndex) {
if (mediaItemIndex == SessionPlayer.INVALID_ITEM_INDEX) {
return QueueItem.UNKNOWN_ID;
}
return mediaItemIndex;
}
/**
* Convert a {@link ParcelImplListSlice} to a list of {@link MediaItem}.
*/
public static List<MediaItem> convertParcelImplListSliceToMediaItemList(
ParcelImplListSlice listSlice) {
if (listSlice == null) {
return null;
}
List<ParcelImpl> parcelImplList = listSlice.getList();
List<MediaItem> mediaItemList = new ArrayList<>();
for (int i = 0; i < parcelImplList.size(); i++) {
final ParcelImpl itemParcelImpl = parcelImplList.get(i);
if (itemParcelImpl != null) {
mediaItemList.add((MediaItem) MediaParcelUtils.fromParcelable(itemParcelImpl));
}
}
return mediaItemList;
}
/**
* Return a list which consists of first {@code N} items of the given list with the same order.
* {@code N} is determined as the maximum number of items whose total parcelled size is less
* than {@param sizeLimitInBytes}.
*/
public static <T extends Parcelable> List<T> truncateListBySize(final List<T> list,
final int sizeLimitInBytes) {
if (list == null) {
return null;
}
List<T> result = new ArrayList<>();
Parcel parcel = Parcel.obtain();
try {
for (int i = 0; i < list.size(); i++) {
// Calculate the size.
T item = list.get(i);
parcel.writeParcelable(item, 0);
if (parcel.dataSize() < sizeLimitInBytes) {
result.add(item);
} else {
break;
}
}
return result;
} finally {
parcel.recycle();
}
}
/**
* Creates a {@link MediaMetadata} from the {@link MediaDescriptionCompat}.
*
* @param descCompat A {@link MediaDescriptionCompat} object.
* @param browsable {@code true} if it's from {@link MediaBrowserCompat.MediaItem} with
* browsable flag.
* @param playable {@code true} if it's from {@link MediaBrowserCompat.MediaItem} with
* playable flag, or from {@link QueueItem}.
* @return
*/
private static MediaMetadata convertToMediaMetadata(MediaDescriptionCompat descCompat,
boolean browsable, boolean playable) {
if (descCompat == null) {
return null;
}
MediaMetadata.Builder metadataBuilder = new MediaMetadata.Builder();
metadataBuilder.putString(METADATA_KEY_MEDIA_ID, descCompat.getMediaId());
CharSequence title = descCompat.getTitle();
if (title != null) {
metadataBuilder.putText(METADATA_KEY_DISPLAY_TITLE, title);
}
CharSequence description = descCompat.getDescription();
if (description != null) {
metadataBuilder.putText(METADATA_KEY_DISPLAY_DESCRIPTION, descCompat.getDescription());
}
CharSequence subtitle = descCompat.getSubtitle();
if (subtitle != null) {
metadataBuilder.putText(METADATA_KEY_DISPLAY_SUBTITLE, subtitle);
}
Bitmap icon = descCompat.getIconBitmap();
if (icon != null) {
metadataBuilder.putBitmap(METADATA_KEY_DISPLAY_ICON, icon);
}
Uri iconUri = descCompat.getIconUri();
if (iconUri != null) {
metadataBuilder.putText(METADATA_KEY_DISPLAY_ICON_URI, iconUri.toString());
}
Bundle bundle = descCompat.getExtras();
if (bundle != null) {
metadataBuilder.setExtras(bundle);
}
Uri mediaUri = descCompat.getMediaUri();
if (mediaUri != null) {
metadataBuilder.putText(METADATA_KEY_MEDIA_URI, mediaUri.toString());
}
if (bundle != null && bundle.containsKey(EXTRA_BT_FOLDER_TYPE)) {
metadataBuilder.putLong(METADATA_KEY_BROWSABLE,
bundle.getLong(EXTRA_BT_FOLDER_TYPE));
} else if (browsable) {
metadataBuilder.putLong(METADATA_KEY_BROWSABLE, BROWSABLE_TYPE_MIXED);
} else {
metadataBuilder.putLong(METADATA_KEY_BROWSABLE, BROWSABLE_TYPE_NONE);
}
metadataBuilder.putLong(METADATA_KEY_PLAYABLE, playable ? 1 : 0);
return metadataBuilder.build();
}
/**
* Creates a {@link MediaMetadata} from the {@link CharSequence}.
*/
public static MediaMetadata convertToMediaMetadata(CharSequence queueTitle) {
if (queueTitle == null) {
return null;
}
return new MediaMetadata.Builder()
.putString(METADATA_KEY_TITLE, queueTitle.toString())
.putLong(METADATA_KEY_BROWSABLE, BROWSABLE_TYPE_MIXED)
.putLong(METADATA_KEY_PLAYABLE, 1)
.build();
}
/**
* Creates a {@link MediaMetadataCompat} from the {@link MediaMetadata}.
*
* @param metadata A {@link MediaMetadata} object.
* @return The newly created {@link MediaMetadataCompat} object.
*/
public static MediaMetadataCompat convertToMediaMetadataCompat(MediaMetadata metadata) {
if (metadata == null) {
return null;
}
MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder();
for (String key : metadata.keySet()) {
String compatKey = METADATA_KEY_TO_METADATA_COMPAT_KEY.containsKey(key)
? METADATA_KEY_TO_METADATA_COMPAT_KEY.get(key) : key;
Object value = metadata.getObject(key);
if (value instanceof CharSequence) {
builder.putText(compatKey, (CharSequence) value);
} else if (value instanceof Bitmap) {
builder.putBitmap(compatKey, (Bitmap) value);
} else if (value instanceof Long) {
builder.putLong(compatKey, (Long) value);
} else if (value instanceof Bundle && !TextUtils.equals(key, METADATA_KEY_EXTRAS)) {
// Must be Bundle which contains a Rating.
// Use MediaMetadata#getRating(key) to get a Rating object.
try {
Rating rating = metadata.getRating(key);
builder.putRating(compatKey, MediaUtils.convertToRatingCompat(rating));
} catch (Exception e) {
// Prevent from CastException in the getRating() due to the future changes.
}
}
}
return builder.build();
}
/**
* Creates a {@link Rating} from the {@link RatingCompat}.
*
* @param ratingCompat A {@link RatingCompat} object.
* @return The newly created {@link Rating} object.
*/
public static Rating convertToRating(RatingCompat ratingCompat) {
if (ratingCompat == null) {
return null;
}
switch (ratingCompat.getRatingStyle()) {
case RatingCompat.RATING_3_STARS:
return ratingCompat.isRated()
? new StarRating(3, ratingCompat.getStarRating()) : new StarRating(3);
case RatingCompat.RATING_4_STARS:
return ratingCompat.isRated()
? new StarRating(4, ratingCompat.getStarRating()) : new StarRating(4);
case RatingCompat.RATING_5_STARS:
return ratingCompat.isRated()
? new StarRating(5, ratingCompat.getStarRating()) : new StarRating(5);
case RatingCompat.RATING_HEART:
return ratingCompat.isRated()
? new HeartRating(ratingCompat.hasHeart()) : new HeartRating();
case RatingCompat.RATING_THUMB_UP_DOWN:
return ratingCompat.isRated()
? new ThumbRating(ratingCompat.isThumbUp()) : new ThumbRating();
case RatingCompat.RATING_PERCENTAGE:
return ratingCompat.isRated()
? new PercentageRating(ratingCompat.getPercentRating())
: new PercentageRating();
default:
return null;
}
}
/**
* Creates a {@link RatingCompat} from the {@link Rating}.
*
* @param rating A {@link Rating} object.
* @return The newly created {@link RatingCompat} object.
*/
@SuppressLint("WrongConstant") // for @StarStyle
public static RatingCompat convertToRatingCompat(Rating rating) {
if (rating == null) {
return null;
}
int ratingCompatStyle = getRatingCompatStyle(rating);
if (!rating.isRated()) {
return RatingCompat.newUnratedRating(ratingCompatStyle);
}
switch (ratingCompatStyle) {
case RatingCompat.RATING_3_STARS:
case RatingCompat.RATING_4_STARS:
case RatingCompat.RATING_5_STARS:
return RatingCompat.newStarRating(
ratingCompatStyle, ((StarRating) rating).getStarRating());
case RatingCompat.RATING_HEART:
return RatingCompat.newHeartRating(((HeartRating) rating).hasHeart());
case RatingCompat.RATING_THUMB_UP_DOWN:
return RatingCompat.newThumbRating(((ThumbRating) rating).isThumbUp());
case RatingCompat.RATING_PERCENTAGE:
return RatingCompat.newPercentageRating(
((PercentageRating) rating).getPercentRating());
default:
return null;
}
}
/**
* Convert a list of {@link CommandButton} to a list of {@link ParcelImpl}.
*/
public static List<ParcelImpl> convertCommandButtonListToParcelImplList(
List<CommandButton> commandButtonList) {
if (commandButtonList == null) {
return null;
}
List<ParcelImpl> parcelImplList = new ArrayList<>();
for (int i = 0; i < commandButtonList.size(); i++) {
final CommandButton commandButton = commandButtonList.get(i);
parcelImplList.add(MediaParcelUtils.toParcelable(commandButton));
}
return parcelImplList;
}
/**
* Convert a list of {@link MediaItem} to a list of {@link ParcelImplListSlice}.
*/
public static ParcelImplListSlice convertMediaItemListToParcelImplListSlice(
List<MediaItem> mediaItemList) {
if (mediaItemList == null) {
return null;
}
List<ParcelImpl> itemParcelableList = new ArrayList<>();
for (int i = 0; i < mediaItemList.size(); i++) {
final MediaItem item = mediaItemList.get(i);
if (item != null) {
final ParcelImpl itemParcelImpl = MediaParcelUtils.toParcelable(item);
itemParcelableList.add(itemParcelImpl);
}
}
return new ParcelImplListSlice(itemParcelableList);
}
/**
* Convert a {@link SessionPlayer.PlayerState} and
* {@link SessionPlayer.BuffState} into {@link PlaybackStateCompat.State}.
*/
public static int convertToPlaybackStateCompatState(int playerState, int bufferingState) {
switch (playerState) {
case SessionPlayer.PLAYER_STATE_PLAYING:
switch (bufferingState) {
case SessionPlayer.BUFFERING_STATE_BUFFERING_AND_STARVED:
return PlaybackStateCompat.STATE_BUFFERING;
}
return PlaybackStateCompat.STATE_PLAYING;
case SessionPlayer.PLAYER_STATE_PAUSED:
return PlaybackStateCompat.STATE_PAUSED;
case SessionPlayer.PLAYER_STATE_IDLE:
return PlaybackStateCompat.STATE_NONE;
case SessionPlayer.PLAYER_STATE_ERROR:
return PlaybackStateCompat.STATE_ERROR;
}
// For unknown value
return PlaybackStateCompat.STATE_ERROR;
}
/**
* Convert a {@link PlaybackStateCompat} into {@link SessionPlayer.PlayerState}.
*/
public static int convertToPlayerState(PlaybackStateCompat state) {
if (state == null) {
return SessionPlayer.PLAYER_STATE_IDLE;
}
switch (state.getState()) {
case PlaybackStateCompat.STATE_ERROR:
return SessionPlayer.PLAYER_STATE_ERROR;
case PlaybackStateCompat.STATE_NONE:
return SessionPlayer.PLAYER_STATE_IDLE;
case PlaybackStateCompat.STATE_PAUSED:
case PlaybackStateCompat.STATE_STOPPED:
case PlaybackStateCompat.STATE_BUFFERING: // means paused for buffering.
return SessionPlayer.PLAYER_STATE_PAUSED;
case PlaybackStateCompat.STATE_FAST_FORWARDING:
case PlaybackStateCompat.STATE_PLAYING:
case PlaybackStateCompat.STATE_REWINDING:
case PlaybackStateCompat.STATE_SKIPPING_TO_NEXT:
case PlaybackStateCompat.STATE_SKIPPING_TO_PREVIOUS:
case PlaybackStateCompat.STATE_SKIPPING_TO_QUEUE_ITEM:
case PlaybackStateCompat.STATE_CONNECTING: // Note: there's no perfect match for this.
return SessionPlayer.PLAYER_STATE_PLAYING;
}
return SessionPlayer.PLAYER_STATE_ERROR;
}
/**
* Convert a {@link PlaybackStateCompat.State} into {@link SessionPlayer.BuffState}.
*/
// Note: there's no perfect match for this.
public static int toBufferingState(int playbackStateCompatState) {
switch (playbackStateCompatState) {
case PlaybackStateCompat.STATE_BUFFERING:
return SessionPlayer.BUFFERING_STATE_BUFFERING_AND_STARVED;
case PlaybackStateCompat.STATE_PLAYING:
return SessionPlayer.BUFFERING_STATE_COMPLETE;
default:
return SessionPlayer.BUFFERING_STATE_UNKNOWN;
}
}
/**
* Convert a {@link MediaControllerCompat.PlaybackInfo} into
* {@link MediaController.PlaybackInfo}.
*/
public static MediaController.PlaybackInfo toPlaybackInfo2(
MediaControllerCompat.PlaybackInfo info) {
return MediaController.PlaybackInfo.createPlaybackInfo(info.getPlaybackType(),
new AudioAttributesCompat.Builder().setLegacyStreamType(
info.getAudioAttributes().getLegacyStreamType()).build(),
info.getVolumeControl(), info.getMaxVolume(), info.getCurrentVolume());
}
/**
* Returns whether the bundle is not parcelable.
*/
public static boolean isUnparcelableBundle(Bundle bundle) {
if (bundle == null) {
return false;
}
bundle.setClassLoader(MediaUtils.class.getClassLoader());
try {
bundle.size();
} catch (Exception e) {
return true;
}
return false;
}
/**
* Removes unparcelable bundles in the given list.
*/
public static void keepUnparcelableBundlesOnly(final List<Bundle> bundles) {
if (bundles == null) {
return;
}
for (int i = bundles.size() - 1; i >= 0; --i) {
Bundle bundle = bundles.get(i);
if (isUnparcelableBundle(bundle)) {
bundles.remove(i);
}
}
}
private static @RatingCompat.Style int getRatingCompatStyle(Rating rating) {
if (rating instanceof HeartRating) {
return RatingCompat.RATING_HEART;
} else if (rating instanceof ThumbRating) {
return RatingCompat.RATING_THUMB_UP_DOWN;
} else if (rating instanceof StarRating) {
switch (((StarRating) rating).getMaxStars()) {
case 3:
return RatingCompat.RATING_3_STARS;
case 4:
return RatingCompat.RATING_4_STARS;
case 5:
return RatingCompat.RATING_5_STARS;
}
} else if (rating instanceof PercentageRating) {
return RatingCompat.RATING_PERCENTAGE;
}
return RatingCompat.RATING_NONE;
}
/**
* Converts the rootHints, option, and extra to the {@link LibraryParams}.
*
* @param legacyBundle
* @return new LibraryParams
*/
@Nullable
public static LibraryParams convertToLibraryParams(@NonNull Context context,
@Nullable Bundle legacyBundle) {
if (legacyBundle == null) {
return null;
}
try {
legacyBundle.setClassLoader(context.getClassLoader());
return new LibraryParams.Builder().setExtras(legacyBundle)
.setRecent(legacyBundle.getBoolean(BrowserRoot.EXTRA_RECENT))
.setOffline(legacyBundle.getBoolean(BrowserRoot.EXTRA_OFFLINE))
.setSuggested(legacyBundle.getBoolean(BrowserRoot.EXTRA_SUGGESTED))
.build();
} catch (Exception e) {
// Failure when unpacking the legacy bundle.
return new LibraryParams.Builder().setExtras(legacyBundle).build();
}
}
/**
* Converts {@link LibraryParams} to the root hints.
*
* @param params
* @return new root hints
*/
@Nullable
public static Bundle convertToRootHints(@Nullable LibraryParams params) {
if (params == null) {
return null;
}
Bundle rootHints = (params.getExtras() == null)
? new Bundle() : new Bundle(params.getExtras());
rootHints.putBoolean(BrowserRoot.EXTRA_RECENT, params.isRecent());
rootHints.putBoolean(BrowserRoot.EXTRA_OFFLINE, params.isOffline());
rootHints.putBoolean(BrowserRoot.EXTRA_SUGGESTED, params.isSuggested());
return rootHints;
}
/**
* Removes all null elements from the list and returns it.
*
* @param list
* @return
*/
@Nullable
public static <T> List<T> removeNullElements(@Nullable List<T> list) {
if (list == null) {
return null;
}
List<T> newList = new ArrayList<>();
for (T item : list) {
if (item != null) {
newList.add(item);
}
}
return newList;
}
/**
* Converts {@link MediaControllerCompat#getFlags() session flags} and
* {@link PlaybackStateCompat} to the {@link SessionCommandGroup}.
* <p>
* This ignores {@link PlaybackStateCompat#getActions() actions} in the
* {@link PlaybackStateCompat} to workaround media apps' issues that they don't set playback
* state correctly.
*
* @param sessionFlags session flag
* @param state playback state
* @return the converted session command group
*/
@NonNull
public static SessionCommandGroup convertToSessionCommandGroup(long sessionFlags,
@Nullable PlaybackStateCompat state) {
SessionCommandGroup.Builder commandsBuilder = new SessionCommandGroup.Builder();
// MediaSessionCompat only support COMMAND_VERSION_1.
commandsBuilder.addAllPlayerBasicCommands(COMMAND_VERSION_1);
boolean includePlaylistCommands = (sessionFlags & FLAG_HANDLES_QUEUE_COMMANDS) != 0;
if (includePlaylistCommands) {
commandsBuilder.addAllPlayerPlaylistCommands(COMMAND_VERSION_1);
}
commandsBuilder.addAllVolumeCommands(COMMAND_VERSION_1);
commandsBuilder.addAllSessionCommands(COMMAND_VERSION_1);
commandsBuilder.removeCommand(new SessionCommand(COMMAND_CODE_PLAYER_SET_SPEED));
commandsBuilder.removeCommand(new SessionCommand(COMMAND_CODE_PLAYER_SET_SURFACE));
commandsBuilder.removeCommand(new SessionCommand(COMMAND_CODE_PLAYER_SELECT_TRACK));
commandsBuilder.removeCommand(new SessionCommand(COMMAND_CODE_PLAYER_DESELECT_TRACK));
if (state != null && state.getCustomActions() != null) {
for (CustomAction customAction : state.getCustomActions()) {
commandsBuilder.addCommand(
new SessionCommand(customAction.getAction(), customAction.getExtras()));
}
}
return commandsBuilder.build();
}
/**
* Converts {@link CustomAction} in the {@link PlaybackStateCompat} to the custom layout which
* is the list of the {@link CommandButton}.
*
* @param state playback state
* @return custom layout. Always non-null.
*/
@NonNull
public static List<CommandButton> convertToCustomLayout(@Nullable PlaybackStateCompat state) {
List<CommandButton> layout = new ArrayList<>();
if (state == null) {
return layout;
}
for (CustomAction action : state.getCustomActions()) {
CommandButton button = new CommandButton.Builder()
.setCommand(new SessionCommand(action.getAction(), action.getExtras()))
.setDisplayName(action.getName())
.setEnabled(true)
.setIconResId(action.getIcon()).build();
layout.add(button);
}
return layout;
}
/**
* Gets the legacy stream type from {@link androidx.media.AudioAttributesCompat}.
*
* @param attrs audio attributes
* @return int legacy stream type from {@link AudioManager}
*/
public static int getLegacyStreamType(@Nullable AudioAttributesCompat attrs) {
int stream;
if (attrs == null) {
stream = AudioManager.STREAM_MUSIC;
} else {
stream = attrs.getLegacyStreamType();
if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) {
// Usually, AudioAttributesCompat#getLegacyStreamType() does not return
// USE_DEFAULT_STREAM_TYPE unless the developer sets it with
// AudioAttributesCompat.Builder#setLegacyStreamType().
// But for safety, let's convert USE_DEFAULT_STREAM_TYPE to STREAM_MUSIC here.
stream = AudioManager.STREAM_MUSIC;
}
}
return stream;
}
@SuppressWarnings({"ParcelClassLoader", "deprecation"})
static boolean doesBundleHaveCustomParcelable(@NonNull Bundle bundle) {
// Try writing the bundle to parcel, and read it with framework classloader.
Parcel parcel = Parcel.obtain();
try {
parcel.writeBundle(bundle);
parcel.setDataPosition(0);
Bundle out = parcel.readBundle(null);
for (String key : out.keySet()) {
// Attempt to retrieve all Bundle values with the framework class loader.
out.get(key);
}
return false;
} catch (BadParcelableException e) {
Log.d(TAG, "Custom parcelables are not allowed", e);
return true;
} finally {
parcel.recycle();
}
}
}