Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright 2018 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.media;
     18 
     19 import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
     20 
     21 import android.os.Bundle;
     22 import android.text.TextUtils;
     23 
     24 import androidx.annotation.IntDef;
     25 import androidx.annotation.NonNull;
     26 import androidx.annotation.Nullable;
     27 import androidx.annotation.RestrictTo;
     28 
     29 import java.lang.annotation.Retention;
     30 import java.lang.annotation.RetentionPolicy;
     31 import java.util.UUID;
     32 
     33 /**
     34  * A class with information on a single media item with the metadata information.
     35  * Media item are application dependent so we cannot guarantee that they contain the right values.
     36  * <p>
     37  * When it's sent to a controller or browser, it's anonymized and data descriptor wouldn't be sent.
     38  * <p>
     39  * This object isn't a thread safe.
     40  */
     41 public class MediaItem2 {
     42     /** @hide */
     43     @RestrictTo(LIBRARY_GROUP)
     44     @Retention(RetentionPolicy.SOURCE)
     45     @IntDef(flag = true, value = { FLAG_BROWSABLE, FLAG_PLAYABLE })
     46     public @interface Flags { }
     47 
     48     /**
     49      * Flag: Indicates that the item has children of its own.
     50      */
     51     public static final int FLAG_BROWSABLE = 1 << 0;
     52 
     53     /**
     54      * Flag: Indicates that the item is playable.
     55      * <p>
     56      * The id of this item may be passed to
     57      * {@link MediaController2#playFromMediaId(String, Bundle)}
     58      */
     59     public static final int FLAG_PLAYABLE = 1 << 1;
     60 
     61     private static final String KEY_ID = "android.media.mediaitem2.id";
     62     private static final String KEY_FLAGS = "android.media.mediaitem2.flags";
     63     private static final String KEY_METADATA = "android.media.mediaitem2.metadata";
     64     private static final String KEY_UUID = "android.media.mediaitem2.uuid";
     65 
     66     private final String mId;
     67     private final int mFlags;
     68     private final UUID mUUID;
     69     private MediaMetadata2 mMetadata;
     70     private DataSourceDesc mDataSourceDesc;
     71 
     72     private MediaItem2(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
     73             @Nullable MediaMetadata2 metadata, @Flags int flags) {
     74         this(mediaId, dsd, metadata, flags, null);
     75     }
     76 
     77     private MediaItem2(@NonNull String mediaId, @Nullable DataSourceDesc dsd,
     78             @Nullable MediaMetadata2 metadata, @Flags int flags, @Nullable UUID uuid) {
     79         if (mediaId == null) {
     80             throw new IllegalArgumentException("mediaId shouldn't be null");
     81         }
     82         if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) {
     83             throw new IllegalArgumentException("metadata's id should be matched with the mediaid");
     84         }
     85 
     86         mId = mediaId;
     87         mDataSourceDesc = dsd;
     88         mMetadata = metadata;
     89         mFlags = flags;
     90         mUUID = (uuid == null) ? UUID.randomUUID() : uuid;
     91     }
     92     /**
     93      * Return this object as a bundle to share between processes.
     94      *
     95      * @return a new bundle instance
     96      */
     97     public Bundle toBundle() {
     98         Bundle bundle = new Bundle();
     99         bundle.putString(KEY_ID, mId);
    100         bundle.putInt(KEY_FLAGS, mFlags);
    101         if (mMetadata != null) {
    102             bundle.putBundle(KEY_METADATA, mMetadata.toBundle());
    103         }
    104         bundle.putString(KEY_UUID, mUUID.toString());
    105         return bundle;
    106     }
    107 
    108     /**
    109      * Create a MediaItem2 from the {@link Bundle}.
    110      *
    111      * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
    112      * @return The newly created MediaItem2
    113      */
    114     public static MediaItem2 fromBundle(Bundle bundle) {
    115         if (bundle == null) {
    116             return null;
    117         }
    118         final String uuidString = bundle.getString(KEY_UUID);
    119         return fromBundle(bundle, UUID.fromString(uuidString));
    120     }
    121 
    122     /**
    123      * Create a MediaItem2 from the {@link Bundle} with the specified {@link UUID}.
    124      * If {@link UUID}
    125      * can be null for creating new.
    126      *
    127      * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}.
    128      * @param uuid A {@link UUID} to override. Can be {@link null} for override.
    129      * @return The newly created MediaItem2
    130      */
    131     static MediaItem2 fromBundle(@NonNull Bundle bundle, @Nullable UUID uuid) {
    132         if (bundle == null) {
    133             return null;
    134         }
    135         final String id = bundle.getString(KEY_ID);
    136         final Bundle metadataBundle = bundle.getBundle(KEY_METADATA);
    137         final MediaMetadata2 metadata = metadataBundle != null
    138                 ? MediaMetadata2.fromBundle(metadataBundle) : null;
    139         final int flags = bundle.getInt(KEY_FLAGS);
    140         return new MediaItem2(id, null, metadata, flags, uuid);
    141     }
    142 
    143     @Override
    144     public String toString() {
    145         final StringBuilder sb = new StringBuilder("MediaItem2{");
    146         sb.append("mFlags=").append(mFlags);
    147         sb.append(", mMetadata=").append(mMetadata);
    148         sb.append('}');
    149         return sb.toString();
    150     }
    151 
    152     /**
    153      * Gets the flags of the item.
    154      */
    155     public @Flags int getFlags() {
    156         return mFlags;
    157     }
    158 
    159     /**
    160      * Returns whether this item is browsable.
    161      * @see #FLAG_BROWSABLE
    162      */
    163     public boolean isBrowsable() {
    164         return (mFlags & FLAG_BROWSABLE) != 0;
    165     }
    166 
    167     /**
    168      * Returns whether this item is playable.
    169      * @see #FLAG_PLAYABLE
    170      */
    171     public boolean isPlayable() {
    172         return (mFlags & FLAG_PLAYABLE) != 0;
    173     }
    174 
    175     /**
    176      * Set a metadata. If the metadata is not null, its id should be matched with this instance's
    177      * media id.
    178      *
    179      * @param metadata metadata to update
    180      */
    181     public void setMetadata(@Nullable MediaMetadata2 metadata) {
    182         if (metadata != null && !TextUtils.equals(mId, metadata.getMediaId())) {
    183             throw new IllegalArgumentException("metadata's id should be matched with the mediaId");
    184         }
    185         mMetadata = metadata;
    186     }
    187 
    188     /**
    189      * Returns the metadata of the media.
    190      */
    191     public @Nullable MediaMetadata2 getMetadata() {
    192         return mMetadata;
    193     }
    194 
    195     /**
    196      * Returns the media id for this item.
    197      */
    198     public /*@NonNull*/ String getMediaId() {
    199         return mId;
    200     }
    201 
    202     /**
    203      * Return the {@link DataSourceDesc}
    204      * <p>
    205      * Can be {@code null} if the MediaItem2 came from another process and anonymized
    206      *
    207      * @return data source descriptor
    208      */
    209     public @Nullable DataSourceDesc getDataSourceDesc() {
    210         return mDataSourceDesc;
    211     }
    212 
    213     @Override
    214     public int hashCode() {
    215         return mUUID.hashCode();
    216     }
    217 
    218     @Override
    219     public boolean equals(Object obj) {
    220         if (!(obj instanceof MediaItem2)) {
    221             return false;
    222         }
    223         MediaItem2 other = (MediaItem2) obj;
    224         return mUUID.equals(other.mUUID);
    225     }
    226 
    227     /**
    228      * Build {@link MediaItem2}
    229      */
    230     public static final class Builder {
    231         private @Flags int mFlags;
    232         private String mMediaId;
    233         private MediaMetadata2 mMetadata;
    234         private DataSourceDesc mDataSourceDesc;
    235 
    236         /**
    237          * Constructor for {@link Builder}
    238          *
    239          * @param flags
    240          */
    241         public Builder(@Flags int flags) {
    242             mFlags = flags;
    243         }
    244 
    245         /**
    246          * Set the media id of this instance. {@code null} for unset.
    247          * <p>
    248          * Media id is used to identify a media contents between session and controller.
    249          * <p>
    250          * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
    251          * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
    252          * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
    253          * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
    254          *
    255          * @param mediaId media id
    256          * @return this instance for chaining
    257          */
    258         public Builder setMediaId(@Nullable String mediaId) {
    259             mMediaId = mediaId;
    260             return this;
    261         }
    262 
    263         /**
    264          * Set the metadata of this instance. {@code null} for unset.
    265          * <p>
    266          * If the metadata is set with the {@link #setMetadata(MediaMetadata2)} and it has
    267          * media id, id from {@link #setMediaId(String)} will be ignored and metadata's id will be
    268          * used instead. If the id isn't set neither by {@link #setMediaId(String)} nor
    269          * {@link #setMetadata(MediaMetadata2)}, id will be automatically generated.
    270          *
    271          * @param metadata metadata
    272          * @return this instance for chaining
    273          */
    274         public Builder setMetadata(@Nullable MediaMetadata2 metadata) {
    275             mMetadata = metadata;
    276             return this;
    277         }
    278 
    279         /**
    280          * Set the data source descriptor for this instance. {@code null} for unset.
    281          *
    282          * @param dataSourceDesc data source descriptor
    283          * @return this instance for chaining
    284          */
    285         public Builder setDataSourceDesc(@Nullable DataSourceDesc dataSourceDesc) {
    286             mDataSourceDesc = dataSourceDesc;
    287             return this;
    288         }
    289 
    290         /**
    291          * Build {@link MediaItem2}.
    292          *
    293          * @return a new {@link MediaItem2}.
    294          */
    295         public MediaItem2 build() {
    296             String id = (mMetadata != null)
    297                     ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null;
    298             if (id == null) {
    299                 id = (mMediaId != null) ? mMediaId : toString();
    300             }
    301             return new MediaItem2(id, mDataSourceDesc, mMetadata, mFlags);
    302         }
    303     }
    304 }
    305