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