• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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.bluetooth.audio_util;
18 
19 import android.content.Context;
20 import android.media.MediaDescription;
21 import android.media.MediaMetadata;
22 import android.media.browse.MediaBrowser.MediaItem;
23 import android.media.session.MediaSession;
24 import android.os.Bundle;
25 
26 import java.util.Objects;
27 
28 public class Metadata implements Cloneable {
29     public String mediaId;
30     public String title;
31     public String artist;
32     public String album;
33     public String trackNum;
34     public String numTracks;
35     public String genre;
36     public String duration;
37     public Image image;
38 
39     @Override
clone()40     public Metadata clone() {
41         Metadata data = new Metadata();
42         data.mediaId = mediaId;
43         data.title = title;
44         data.artist = artist;
45         data.album = album;
46         data.trackNum = trackNum;
47         data.numTracks = numTracks;
48         data.genre = genre;
49         data.duration = duration;
50         data.image = image;
51         return data;
52     }
53 
54     @Override
equals(Object o)55     public boolean equals(Object o) {
56         if (o == null) return false;
57         if (!(o instanceof Metadata)) return false;
58 
59         final Metadata m = (Metadata) o;
60         if (!Objects.equals(title, m.title)) return false;
61         if (!Objects.equals(artist, m.artist)) return false;
62         if (!Objects.equals(album, m.album)) return false;
63         if (!Objects.equals(trackNum, m.trackNum)) return false;
64         if (!Objects.equals(numTracks, m.numTracks)) return false;
65         if (!Objects.equals(image, m.image)) return false;
66         return true;
67     }
68 
69     @Override
toString()70     public String toString() {
71         return "{ mediaId=\"" + mediaId + "\" title=\"" + title + "\" artist=\"" + artist
72                 + "\" album=\"" + album + "\" duration=" + duration
73                 + " trackPosition=" + trackNum + "/" + numTracks + " image=" + image + " }";
74     }
75 
76     /**
77      * A Builder object to populate a Metadata from various different Media Framework objects
78      */
79     public static class Builder {
80         private Metadata mMetadata = new Metadata();
81         private Context mContext = null;
82 
83         /**
84          * Set the Media ID fot the Metadata Object
85          */
setMediaId(String id)86         public Builder setMediaId(String id) {
87             mMetadata.mediaId = id;
88             return this;
89         }
90 
91         /**
92          * Set the context this builder should use when resolving images
93          */
useContext(Context context)94         public Builder useContext(Context context) {
95             mContext = context;
96             return this;
97         }
98 
99         /**
100          * Extract the fields from a MediaMetadata object into a Metadata, if they exist
101          */
fromMediaMetadata(MediaMetadata data)102         public Builder fromMediaMetadata(MediaMetadata data) {
103             if (data == null) return this;
104 
105             // First, use the basic description available with the MediaMetadata
106             fromMediaDescription(data.getDescription());
107 
108             // Then, replace with better data if available on the MediaMetadata
109             if (data.containsKey(MediaMetadata.METADATA_KEY_MEDIA_ID)) {
110                 mMetadata.mediaId = data.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
111             }
112             if (data.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
113                 mMetadata.title = data.getString(MediaMetadata.METADATA_KEY_TITLE);
114             }
115             if (data.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
116                 mMetadata.artist = data.getString(MediaMetadata.METADATA_KEY_ARTIST);
117             }
118             if (data.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
119                 mMetadata.album = data.getString(MediaMetadata.METADATA_KEY_ALBUM);
120             }
121             if (data.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) {
122                 mMetadata.trackNum = "" + data.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
123             }
124             if (data.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) {
125                 mMetadata.numTracks = "" + data.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS);
126             }
127             if (data.containsKey(MediaMetadata.METADATA_KEY_GENRE)) {
128                 mMetadata.genre = data.getString(MediaMetadata.METADATA_KEY_GENRE);
129             }
130             if (data.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
131                 mMetadata.duration = "" + data.getLong(MediaMetadata.METADATA_KEY_DURATION);
132             }
133             if ((mContext != null && Util.areUriImagesSupported(mContext)
134                     && (data.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
135                     || data.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
136                     || data.containsKey(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI)))
137                     || data.containsKey(MediaMetadata.METADATA_KEY_ART)
138                     || data.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)
139                     || data.containsKey(MediaMetadata.METADATA_KEY_DISPLAY_ICON)) {
140                 mMetadata.image = new Image(mContext, data);
141             }
142             return this;
143         }
144 
145         /**
146          * Extract the fields from a MediaItem object into a Metadata, if they exist
147          */
fromMediaItem(MediaItem item)148         public Builder fromMediaItem(MediaItem item) {
149             if (item == null) return this;
150             return fromMediaDescription(item.getDescription()).setMediaId(item.getMediaId());
151         }
152 
153         /**
154          * Extract the fields from a MediaDescription object into a Metadata, if they exist
155          */
fromMediaDescription(MediaDescription desc)156         public Builder fromMediaDescription(MediaDescription desc) {
157             if (desc == null) return this;
158 
159             // Default the following mapping if they exist
160             if (desc.getTitle() != null) mMetadata.title = desc.getTitle().toString();
161             if (desc.getSubtitle() != null) mMetadata.artist = desc.getSubtitle().toString();
162             if (desc.getDescription() != null) mMetadata.album = desc.getDescription().toString();
163 
164             // Check for artwork
165             if (desc.getIconBitmap() != null) {
166                 mMetadata.image = new Image(mContext, desc.getIconBitmap());
167             } else if (mContext != null && Util.areUriImagesSupported(mContext)
168                     && desc.getIconUri() != null) {
169                 mMetadata.image = new Image(mContext, desc.getIconUri());
170             }
171 
172             // Then, check the extras in the description for even better data
173             return fromBundle(desc.getExtras()).setMediaId(desc.getMediaId());
174         }
175 
176         /**
177          * Extract the fields from a MediaSession.QueueItem object into a Metadata, if they exist
178          */
fromQueueItem(MediaSession.QueueItem item)179         public Builder fromQueueItem(MediaSession.QueueItem item) {
180             if (item == null) return this;
181             return fromMediaDescription(item.getDescription());
182         }
183 
184         /**
185          * Extract the fields from a Bundle of MediaMetadata constants into a Metadata, if they
186          * exist
187          */
fromBundle(Bundle bundle)188         public Builder fromBundle(Bundle bundle) {
189             if (bundle == null) return this;
190             if (bundle.containsKey(MediaMetadata.METADATA_KEY_MEDIA_ID)) {
191                 mMetadata.mediaId = bundle.getString(MediaMetadata.METADATA_KEY_MEDIA_ID);
192             }
193             if (bundle.containsKey(MediaMetadata.METADATA_KEY_TITLE)) {
194                 mMetadata.title = bundle.getString(MediaMetadata.METADATA_KEY_TITLE);
195             }
196             if (bundle.containsKey(MediaMetadata.METADATA_KEY_ARTIST)) {
197                 mMetadata.artist = bundle.getString(MediaMetadata.METADATA_KEY_ARTIST);
198             }
199             if (bundle.containsKey(MediaMetadata.METADATA_KEY_ALBUM)) {
200                 mMetadata.album = bundle.getString(MediaMetadata.METADATA_KEY_ALBUM);
201             }
202             if (bundle.containsKey(MediaMetadata.METADATA_KEY_TRACK_NUMBER)) {
203                 mMetadata.trackNum = "" + bundle.getLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER);
204             }
205             if (bundle.containsKey(MediaMetadata.METADATA_KEY_NUM_TRACKS)) {
206                 mMetadata.numTracks = "" + bundle.getLong(MediaMetadata.METADATA_KEY_NUM_TRACKS);
207             }
208             if (bundle.containsKey(MediaMetadata.METADATA_KEY_GENRE)) {
209                 mMetadata.genre = bundle.getString(MediaMetadata.METADATA_KEY_GENRE);
210             }
211             if (bundle.containsKey(MediaMetadata.METADATA_KEY_DURATION)) {
212                 mMetadata.duration = "" + bundle.getLong(MediaMetadata.METADATA_KEY_DURATION);
213             }
214             if ((mContext != null && Util.areUriImagesSupported(mContext)
215                     && (bundle.containsKey(MediaMetadata.METADATA_KEY_ART_URI)
216                     || bundle.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART_URI)
217                     || bundle.containsKey(MediaMetadata.METADATA_KEY_DISPLAY_ICON_URI)))
218                     || bundle.containsKey(MediaMetadata.METADATA_KEY_ART)
219                     || bundle.containsKey(MediaMetadata.METADATA_KEY_ALBUM_ART)
220                     || bundle.containsKey(MediaMetadata.METADATA_KEY_DISPLAY_ICON)) {
221                 mMetadata.image = new Image(mContext, bundle);
222             }
223             return this;
224         }
225 
226         /**
227          * Elect to use default values in the Metadata in place of any missing values
228          */
useDefaults()229         public Builder useDefaults() {
230             if (mMetadata.mediaId == null) mMetadata.mediaId = "Not Provided";
231             if (mMetadata.title == null) mMetadata.title = "Not Provided";
232             if (mMetadata.artist == null) mMetadata.artist = "";
233             if (mMetadata.album == null) mMetadata.album = "";
234             if (mMetadata.trackNum == null) mMetadata.trackNum = "1";
235             if (mMetadata.numTracks == null) mMetadata.numTracks = "1";
236             if (mMetadata.genre == null) mMetadata.genre = "";
237             if (mMetadata.duration == null) mMetadata.duration = "0";
238             // The default value chosen for an image is null. Update here if we pick something else
239             return this;
240         }
241 
242         /**
243          * Get the final Metadata objects you're building
244          */
build()245         public Metadata build() {
246             return mMetadata.clone();
247         }
248     }
249 }
250