1a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/* 2a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Copyright (C) 2015 The Android Open Source Project 3a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 4a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Licensed under the Apache License, Version 2.0 (the "License"); 5a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * you may not use this file except in compliance with the License. 6a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * You may obtain a copy of the License at 7a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 8a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * http://www.apache.org/licenses/LICENSE-2.0 9a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 10a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Unless required by applicable law or agreed to in writing, software 11a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * distributed under the License is distributed on an "AS IS" BASIS, 12a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * See the License for the specific language governing permissions and 14a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * limitations under the License. 15a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 16a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 17a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpackage com.example.android.supportv4.media.model; 18a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 19a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.os.AsyncTask; 20a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.support.v4.media.MediaMetadataCompat; 21a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport android.util.Log; 22a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 23a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport org.json.JSONArray; 24a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport org.json.JSONException; 25a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport org.json.JSONObject; 26a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 27a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.BufferedInputStream; 28a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.BufferedReader; 29a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.IOException; 30a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.InputStream; 31a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.io.InputStreamReader; 32a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.net.URL; 33a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.net.URLConnection; 34a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.ArrayList; 35a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.Collections; 36a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.List; 37a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.Set; 38a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.concurrent.ConcurrentHashMap; 39a907614755847b2630561a1e5949b2b416600d97Sungsoo Limimport java.util.concurrent.ConcurrentMap; 40a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 41a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim/** 42a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Utility class to get a list of MusicTrack's based on a server-side JSON 43a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * configuration. 44a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 45a907614755847b2630561a1e5949b2b416600d97Sungsoo Limpublic class MusicProvider { 46a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 47a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String TAG = "MusicProvider"; 48a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 49a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String CATALOG_URL = 50a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim "http://storage.googleapis.com/automotive-media/music.json"; 51a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 52a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__"; 53a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 54a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_MUSIC = "music"; 55a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_TITLE = "title"; 56a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_ALBUM = "album"; 57a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_ARTIST = "artist"; 58a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_GENRE = "genre"; 59a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_SOURCE = "source"; 60a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_IMAGE = "image"; 61a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_TRACK_NUMBER = "trackNumber"; 62a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_TOTAL_TRACK_COUNT = "totalTrackCount"; 63a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private static final String JSON_DURATION = "duration"; 64a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 65a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Categorized caches for music track data: 66a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private ConcurrentMap<String, List<MediaMetadataCompat>> mMusicListByGenre; 673ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon private List<String> mMusicGenres; 68a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final ConcurrentMap<String, MutableMediaMetadata> mMusicListById; 69a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 70a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private final Set<String> mFavoriteTracks; 71a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 72a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim enum State { 73a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim NON_INITIALIZED, INITIALIZING, INITIALIZED 74a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 75a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 76a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private volatile State mCurrentState = State.NON_INITIALIZED; 77a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 78a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public interface Callback { 79a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim void onMusicCatalogReady(boolean success); 80a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 81a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 82a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public MusicProvider() { 83a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMusicListByGenre = new ConcurrentHashMap<>(); 84a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMusicListById = new ConcurrentHashMap<>(); 85a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mFavoriteTracks = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); 863ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon mMusicGenres = new ArrayList<>(); 87a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 88a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 89a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 903ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon * Get the list of genres 91a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 92a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @return genres 93a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 943ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon public List<String> getGenres() { 95a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState != State.INITIALIZED) { 96a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return Collections.emptyList(); 97a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 983ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon return mMusicGenres; 99a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 100a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 101a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 102a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Get music tracks of the given genre 103a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 1043ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon public List<MediaMetadataCompat> getMusicsByGenre(String genre) { 105a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) { 106a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return Collections.emptyList(); 107a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 108a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mMusicListByGenre.get(genre); 109a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 110a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 111a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 112a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Very basic implementation of a search that filter music tracks which title containing 113a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * the given query. 114a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 115a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 116a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public Iterable<MediaMetadataCompat> searchMusic(String titleQuery) { 117a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState != State.INITIALIZED) { 118a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return Collections.emptyList(); 119a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 120a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim ArrayList<MediaMetadataCompat> result = new ArrayList<>(); 121a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim titleQuery = titleQuery.toLowerCase(); 122a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim for (MutableMediaMetadata track : mMusicListById.values()) { 123a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (track.metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE).toLowerCase() 124a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .contains(titleQuery)) { 125a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim result.add(track.metadata); 126a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 127a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 128a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return result; 129a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 130a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 131a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 132a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Return the MediaMetadata for the given musicID. 133a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 134a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @param musicId The unique, non-hierarchical music ID. 135a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 136a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public MediaMetadataCompat getMusic(String musicId) { 137a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId).metadata : null; 138a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 139a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 140a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public synchronized void updateMusic(String musicId, MediaMetadataCompat metadata) { 141a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MutableMediaMetadata track = mMusicListById.get(musicId); 142a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (track == null) { 143a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return; 144a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 145a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 146a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String oldGenre = track.metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); 147a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String newGenre = metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); 148a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 149a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim track.metadata = metadata; 150a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 151a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // if genre has changed, we need to rebuild the list by genre 152a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (!oldGenre.equals(newGenre)) { 153a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim buildListsByGenre(); 154a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 155a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 156a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 157a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void setFavorite(String musicId, boolean favorite) { 158a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (favorite) { 159a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mFavoriteTracks.add(musicId); 160a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } else { 161a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mFavoriteTracks.remove(musicId); 162a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 163a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 164a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 165a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public boolean isFavorite(String musicId) { 166a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mFavoriteTracks.contains(musicId); 167a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 168a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 169a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public boolean isInitialized() { 170a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mCurrentState == State.INITIALIZED; 171a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 172a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 173a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 174a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Get the list of music tracks from a server and caches the track information 175a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * for future reference, keying tracks by musicId and grouping by genre. 176a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 177a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim public void retrieveMediaAsync(final Callback callback) { 178a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "retrieveMediaAsync called"); 179a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState == State.INITIALIZED) { 180a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Nothing to do, execute callback immediately 181a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim callback.onMusicCatalogReady(true); 182a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return; 183a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 184a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 185a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Asynchronously load the music catalog in a separate thread 186a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim new AsyncTask<Void, Void, State>() { 187a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 188a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim protected State doInBackground(Void... params) { 189a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim retrieveMedia(); 190a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return mCurrentState; 191a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 192a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 193a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim @Override 194a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim protected void onPostExecute(State current) { 195a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (callback != null) { 196a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim callback.onMusicCatalogReady(current == State.INITIALIZED); 197a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 198a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 199a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim }.execute(); 200a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 201a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 202a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private synchronized void buildListsByGenre() { 2033ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon ConcurrentMap<String, List<MediaMetadataCompat>> newMusicListByGenre 2043ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon = new ConcurrentHashMap<>(); 205a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 206a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim for (MutableMediaMetadata m : mMusicListById.values()) { 207a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String genre = m.metadata.getString(MediaMetadataCompat.METADATA_KEY_GENRE); 208a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim List<MediaMetadataCompat> list = newMusicListByGenre.get(genre); 209a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (list == null) { 210a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim list = new ArrayList<>(); 211a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim newMusicListByGenre.put(genre, list); 212a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 213a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim list.add(m.metadata); 214a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 215a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMusicListByGenre = newMusicListByGenre; 2163ee2ea199ba4802754fb9108a45ef7c646c0eebbHyundo Moon mMusicGenres = new ArrayList<>(mMusicListByGenre.keySet()); 217a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 218a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 219a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private synchronized void retrieveMedia() { 220a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 221a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState == State.NON_INITIALIZED) { 222a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentState = State.INITIALIZING; 223a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 224a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int slashPos = CATALOG_URL.lastIndexOf('/'); 225a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String path = CATALOG_URL.substring(0, slashPos + 1); 226a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim JSONObject jsonObj = fetchJSONFromUrl(CATALOG_URL); 227a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (jsonObj == null) { 228a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return; 229a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 230a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim JSONArray tracks = jsonObj.getJSONArray(JSON_MUSIC); 231a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (tracks != null) { 232a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim for (int j = 0; j < tracks.length(); j++) { 233a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim MediaMetadataCompat item = buildFromJSON(tracks.getJSONObject(j), path); 234a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String musicId = item.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID); 235a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mMusicListById.put(musicId, new MutableMediaMetadata(musicId, item)); 236a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 237a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim buildListsByGenre(); 238a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 239a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentState = State.INITIALIZED; 240a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 241a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (JSONException e) { 242a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "Could not retrieve music list", e); 243a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } finally { 244a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (mCurrentState != State.INITIALIZED) { 245a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Something bad happened, so we reset state to NON_INITIALIZED to allow 246a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // retries (eg if the network connection is temporary unavailable) 247a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim mCurrentState = State.NON_INITIALIZED; 248a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 249a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 250a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 251a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 252a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private MediaMetadataCompat buildFromJSON(JSONObject json, String basePath) throws JSONException { 253a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String title = json.getString(JSON_TITLE); 254a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String album = json.getString(JSON_ALBUM); 255a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String artist = json.getString(JSON_ARTIST); 256a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String genre = json.getString(JSON_GENRE); 257a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String source = json.getString(JSON_SOURCE); 258a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String iconUrl = json.getString(JSON_IMAGE); 259a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int trackNumber = json.getInt(JSON_TRACK_NUMBER); 260a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int totalTrackCount = json.getInt(JSON_TOTAL_TRACK_COUNT); 261a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim int duration = json.getInt(JSON_DURATION) * 1000; // ms 262a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 263a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.d(TAG, "Found music track: " + json); 264a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 265a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Media is stored relative to JSON file 266a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (!source.startsWith("http")) { 267a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim source = basePath + source; 268a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 269a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (!iconUrl.startsWith("http")) { 270a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim iconUrl = basePath + iconUrl; 271a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 272a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Since we don't have a unique ID in the server, we fake one using the hashcode of 273a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // the music source. In a real world app, this could come from the server. 274a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String id = String.valueOf(source.hashCode()); 275a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 276a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // Adding the music source to the MediaMetadata (and consequently using it in the 277a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // mediaSession.setMetadata) is not a good idea for a real world music app, because 278a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // the session metadata can be accessed by notification listeners. This is done in this 279a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // sample for convenience only. 280a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return new MediaMetadataCompat.Builder() 281a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id) 282a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(CUSTOM_METADATA_TRACK_SOURCE, source) 283a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album) 284a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) 285a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration) 286a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre) 287a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, iconUrl) 288a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) 289a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, trackNumber) 290a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, totalTrackCount) 291a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim .build(); 292a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 293a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim 294a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim /** 295a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * Download a JSON file from a server, parse the content and return the JSON 296a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * object. 297a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * 298a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim * @return result JSONObject containing the parsed representation. 299a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim */ 300a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim private JSONObject fetchJSONFromUrl(String urlString) { 301a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim InputStream is = null; 302a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 303a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim URL url = new URL(urlString); 304a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim URLConnection urlConnection = url.openConnection(); 305a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim is = new BufferedInputStream(urlConnection.getInputStream()); 306a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim BufferedReader reader = new BufferedReader(new InputStreamReader( 307a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim urlConnection.getInputStream(), "iso-8859-1")); 308a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim StringBuilder sb = new StringBuilder(); 309a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim String line; 310a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim while ((line = reader.readLine()) != null) { 311a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim sb.append(line); 312a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 313a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return new JSONObject(sb.toString()); 314a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (Exception e) { 315a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim Log.e(TAG, "Failed to parse the json for media list", e); 316a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim return null; 317a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } finally { 318a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim if (is != null) { 319a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim try { 320a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim is.close(); 321a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } catch (IOException e) { 322a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim // ignore 323a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 324a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 325a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 326a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim } 327a907614755847b2630561a1e5949b2b416600d97Sungsoo Lim} 328