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 com.android.media; 18 19 import static android.media.MediaItem2.FLAG_BROWSABLE; 20 import static android.media.MediaItem2.FLAG_PLAYABLE; 21 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.media.DataSourceDesc; 25 import android.media.MediaItem2; 26 import android.media.MediaItem2.Builder; 27 import android.media.MediaItem2.Flags; 28 import android.media.MediaMetadata2; 29 import android.media.update.MediaItem2Provider; 30 import android.os.Bundle; 31 import android.text.TextUtils; 32 33 import java.util.UUID; 34 35 public class MediaItem2Impl implements MediaItem2Provider { 36 private static final String KEY_ID = "android.media.mediaitem2.id"; 37 private static final String KEY_FLAGS = "android.media.mediaitem2.flags"; 38 private static final String KEY_METADATA = "android.media.mediaitem2.metadata"; 39 private static final String KEY_UUID = "android.media.mediaitem2.uuid"; 40 41 private final MediaItem2 mInstance; 42 private final String mId; 43 private final int mFlags; 44 private final UUID mUUID; 45 private MediaMetadata2 mMetadata; 46 private DataSourceDesc mDataSourceDesc; 47 48 // From the public API 49 public MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd, 50 @Nullable MediaMetadata2 metadata, @Flags int flags) { 51 this(mediaId, dsd, metadata, flags, null); 52 } 53 54 private MediaItem2Impl(@NonNull String mediaId, @Nullable DataSourceDesc dsd, 55 @Nullable MediaMetadata2 metadata, @Flags int flags, @Nullable UUID uuid) { 56 if (mediaId == null) { 57 throw new IllegalArgumentException("mediaId shouldn't be null"); 58 } 59 if (metadata != null && !TextUtils.equals(mediaId, metadata.getMediaId())) { 60 throw new IllegalArgumentException("metadata's id should be matched with the mediaid"); 61 } 62 63 mId = mediaId; 64 mDataSourceDesc = dsd; 65 mMetadata = metadata; 66 mFlags = flags; 67 mUUID = (uuid == null) ? UUID.randomUUID() : uuid; 68 69 mInstance = new MediaItem2(this); 70 } 71 72 @Override 73 public boolean equals_impl(Object obj) { 74 if (!(obj instanceof MediaItem2)) { 75 return false; 76 } 77 MediaItem2 other = (MediaItem2) obj; 78 return mUUID.equals(((MediaItem2Impl) other.getProvider()).mUUID); 79 } 80 81 /** 82 * Return this object as a bundle to share between processes. 83 * 84 * @return a new bundle instance 85 */ 86 public Bundle toBundle_impl() { 87 Bundle bundle = new Bundle(); 88 bundle.putString(KEY_ID, mId); 89 bundle.putInt(KEY_FLAGS, mFlags); 90 if (mMetadata != null) { 91 bundle.putBundle(KEY_METADATA, mMetadata.toBundle()); 92 } 93 bundle.putString(KEY_UUID, mUUID.toString()); 94 return bundle; 95 } 96 97 /** 98 * Create a MediaItem2 from the {@link Bundle}. 99 * 100 * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}. 101 * @return The newly created MediaItem2 102 */ 103 public static MediaItem2 fromBundle_impl(@NonNull Bundle bundle) { 104 if (bundle == null) { 105 return null; 106 } 107 final String uuidString = bundle.getString(KEY_UUID); 108 return fromBundle(bundle, UUID.fromString(uuidString)); 109 } 110 111 /** 112 * Create a MediaItem2 from the {@link Bundle} with the specified {@link UUID}. 113 * If {@link UUID} 114 * can be null for creating new. 115 * 116 * @param bundle The bundle which was published by {@link MediaItem2#toBundle()}. 117 * @param uuid A {@link UUID} to override. Can be {@link null} for override. 118 * @return The newly created MediaItem2 119 */ 120 static MediaItem2 fromBundle(@NonNull Bundle bundle, @Nullable UUID uuid) { 121 if (bundle == null) { 122 return null; 123 } 124 final String id = bundle.getString(KEY_ID); 125 final Bundle metadataBundle = bundle.getBundle(KEY_METADATA); 126 final MediaMetadata2 metadata = MediaMetadata2.fromBundle(metadataBundle); 127 final int flags = bundle.getInt(KEY_FLAGS); 128 return new MediaItem2Impl(id, null, metadata, flags, uuid).getInstance(); 129 } 130 131 private MediaItem2 getInstance() { 132 return mInstance; 133 } 134 135 @Override 136 public String toString_impl() { 137 final StringBuilder sb = new StringBuilder("MediaItem2{"); 138 sb.append("mFlags=").append(mFlags); 139 sb.append(", mMetadata=").append(mMetadata); 140 sb.append('}'); 141 return sb.toString(); 142 } 143 144 @Override 145 public @Flags int getFlags_impl() { 146 return mFlags; 147 } 148 149 @Override 150 public boolean isBrowsable_impl() { 151 return (mFlags & FLAG_BROWSABLE) != 0; 152 } 153 154 @Override 155 public boolean isPlayable_impl() { 156 return (mFlags & FLAG_PLAYABLE) != 0; 157 } 158 159 @Override 160 public void setMetadata_impl(@Nullable MediaMetadata2 metadata) { 161 if (metadata != null && !TextUtils.equals(mId, metadata.getMediaId())) { 162 throw new IllegalArgumentException("metadata's id should be matched with the mediaId"); 163 } 164 mMetadata = metadata; 165 } 166 167 @Override 168 public @Nullable MediaMetadata2 getMetadata_impl() { 169 return mMetadata; 170 } 171 172 @Override 173 public @NonNull String getMediaId_impl() { 174 return mId; 175 } 176 177 @Override 178 public @Nullable DataSourceDesc getDataSourceDesc_impl() { 179 return mDataSourceDesc; 180 } 181 182 public static class BuilderImpl implements MediaItem2Provider.BuilderProvider { 183 private Builder mInstance; 184 private @Flags int mFlags; 185 private String mMediaId; 186 private MediaMetadata2 mMetadata; 187 private DataSourceDesc mDataSourceDesc; 188 189 public BuilderImpl(Builder instance, int flags) { 190 mInstance = instance; 191 mFlags = flags; 192 } 193 194 @Override 195 public Builder setMediaId_impl(@Nullable String mediaId) { 196 mMediaId = mediaId; 197 return mInstance; 198 } 199 200 @Override 201 public Builder setMetadata_impl(@Nullable MediaMetadata2 metadata) { 202 mMetadata = metadata; 203 return mInstance; 204 } 205 206 @Override 207 public Builder setDataSourceDesc_impl(@Nullable DataSourceDesc dataSourceDesc) { 208 mDataSourceDesc = dataSourceDesc; 209 return mInstance; 210 } 211 212 @Override 213 public MediaItem2 build_impl() { 214 String id = (mMetadata != null) 215 ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null; 216 if (id == null) { 217 // TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?) 218 id = (mMediaId != null) ? mMediaId : toString(); 219 } 220 return new MediaItem2Impl(id, mDataSourceDesc, mMetadata, mFlags).getInstance(); 221 } 222 } 223 } 224