diff options
Diffstat (limited to 'MusicDemo/src/main/java/com/example/android/musicservicedemo/model/MusicProvider.java')
-rw-r--r-- | MusicDemo/src/main/java/com/example/android/musicservicedemo/model/MusicProvider.java | 296 |
1 files changed, 0 insertions, 296 deletions
diff --git a/MusicDemo/src/main/java/com/example/android/musicservicedemo/model/MusicProvider.java b/MusicDemo/src/main/java/com/example/android/musicservicedemo/model/MusicProvider.java deleted file mode 100644 index dd89c2d..0000000 --- a/MusicDemo/src/main/java/com/example/android/musicservicedemo/model/MusicProvider.java +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (C) 2014 Google Inc. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.example.android.musicservicedemo.model; - -import android.media.MediaMetadata; -import android.os.AsyncTask; - -import com.example.android.musicservicedemo.utils.LogHelper; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URLConnection; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.locks.ReentrantLock; - -/** - * Utility class to get a list of MusicTrack's based on a server-side JSON - * configuration. - */ -public class MusicProvider { - - private static final String TAG = "MusicProvider"; - - private static final String CATALOG_URL = "http://storage.googleapis.com/automotive-media/music.json"; - - public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__"; - - private static String JSON_MUSIC = "music"; - private static String JSON_TITLE = "title"; - private static String JSON_ALBUM = "album"; - private static String JSON_ARTIST = "artist"; - private static String JSON_GENRE = "genre"; - private static String JSON_SOURCE = "source"; - private static String JSON_IMAGE = "image"; - private static String JSON_TRACK_NUMBER = "trackNumber"; - private static String JSON_TOTAL_TRACK_COUNT = "totalTrackCount"; - private static String JSON_DURATION = "duration"; - - private final ReentrantLock initializationLock = new ReentrantLock(); - - // Categorized caches for music track data: - private final HashMap<String, List<MediaMetadata>> mMusicListByGenre; - private final HashMap<String, MediaMetadata> mMusicListById; - - private final HashSet<String> mFavoriteTracks; - - enum State { - NON_INITIALIZED, INITIALIZING, INITIALIZED; - } - - private State mCurrentState = State.NON_INITIALIZED; - - - public interface Callback { - void onMusicCatalogReady(boolean success); - } - - public MusicProvider() { - mMusicListByGenre = new HashMap<>(); - mMusicListById = new HashMap<>(); - mFavoriteTracks = new HashSet<>(); - } - - /** - * Get an iterator over the list of genres - * - * @return - */ - public Iterable<String> getGenres() { - if (mCurrentState != State.INITIALIZED) { - return new ArrayList<String>(0); - } - return mMusicListByGenre.keySet(); - } - - /** - * Get music tracks of the given genre - * - * @return - */ - public Iterable<MediaMetadata> getMusicsByGenre(String genre) { - if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) { - return new ArrayList<MediaMetadata>(); - } - return mMusicListByGenre.get(genre); - } - - /** - * Very basic implementation of a search that filter music tracks which title containing - * the given query. - * - * @return - */ - public Iterable<MediaMetadata> searchMusics(String titleQuery) { - ArrayList<MediaMetadata> result = new ArrayList<>(); - if (mCurrentState != State.INITIALIZED) { - return result; - } - titleQuery = titleQuery.toLowerCase(); - for (MediaMetadata track: mMusicListById.values()) { - if (track.getString(MediaMetadata.METADATA_KEY_TITLE).toLowerCase() - .contains(titleQuery)) { - result.add(track); - } - } - return result; - } - - public MediaMetadata getMusic(String mediaId) { - return mMusicListById.get(mediaId); - } - - public void setFavorite(String mediaId, boolean favorite) { - if (favorite) { - mFavoriteTracks.add(mediaId); - } else { - mFavoriteTracks.remove(mediaId); - } - } - - public boolean isFavorite(String musicId) { - return mFavoriteTracks.contains(musicId); - } - - public boolean isInitialized() { - return mCurrentState == State.INITIALIZED; - } - - /** - * Get the list of music tracks from a server and caches the track information - * for future reference, keying tracks by mediaId and grouping by genre. - * - * @return - */ - public void retrieveMedia(final Callback callback) { - - if (mCurrentState == State.INITIALIZED) { - // Nothing to do, execute callback immediately - callback.onMusicCatalogReady(true); - return; - } - - // Asynchronously load the music catalog in a separate thread - new AsyncTask() { - @Override - protected Object doInBackground(Object[] objects) { - retrieveMediaAsync(callback); - return null; - } - }.execute(); - } - - private void retrieveMediaAsync(Callback callback) { - initializationLock.lock(); - - try { - if (mCurrentState == State.NON_INITIALIZED) { - mCurrentState = State.INITIALIZING; - - int slashPos = CATALOG_URL.lastIndexOf('/'); - String path = CATALOG_URL.substring(0, slashPos + 1); - JSONObject jsonObj = parseUrl(CATALOG_URL); - - JSONArray tracks = jsonObj.getJSONArray(JSON_MUSIC); - if (tracks != null) { - for (int j = 0; j < tracks.length(); j++) { - MediaMetadata item = buildFromJSON(tracks.getJSONObject(j), path); - String genre = item.getString(MediaMetadata.METADATA_KEY_GENRE); - List<MediaMetadata> list = mMusicListByGenre.get(genre); - if (list == null) { - list = new ArrayList<>(); - } - list.add(item); - mMusicListByGenre.put(genre, list); - mMusicListById.put(item.getString(MediaMetadata.METADATA_KEY_MEDIA_ID), - item); - } - } - mCurrentState = State.INITIALIZED; - } - } catch (RuntimeException | JSONException e) { - LogHelper.e(TAG, e, "Could not retrieve music list"); - } finally { - if (mCurrentState != State.INITIALIZED) { - // Something bad happened, so we reset state to NON_INITIALIZED to allow - // retries (eg if the network connection is temporary unavailable) - mCurrentState = State.NON_INITIALIZED; - } - initializationLock.unlock(); - if (callback != null) { - callback.onMusicCatalogReady(mCurrentState == State.INITIALIZED); - } - } - } - - private MediaMetadata buildFromJSON(JSONObject json, String basePath) throws JSONException { - String title = json.getString(JSON_TITLE); - String album = json.getString(JSON_ALBUM); - String artist = json.getString(JSON_ARTIST); - String genre = json.getString(JSON_GENRE); - String source = json.getString(JSON_SOURCE); - String iconUrl = json.getString(JSON_IMAGE); - int trackNumber = json.getInt(JSON_TRACK_NUMBER); - int totalTrackCount = json.getInt(JSON_TOTAL_TRACK_COUNT); - int duration = json.getInt(JSON_DURATION) * 1000; // ms - - LogHelper.d(TAG, "Found music track: ", json); - - // Media is stored relative to JSON file - if (!source.startsWith("http")) { - source = basePath + source; - } - if (!iconUrl.startsWith("http")) { - iconUrl = basePath + iconUrl; - } - // Since we don't have a unique ID in the server, we fake one using the hashcode of - // the music source. In a real world app, this could come from the server. - String id = String.valueOf(source.hashCode()); - - // Adding the music source to the MediaMetadata (and consequently using it in the - // mediaSession.setMetadata) is not a good idea for a real world music app, because - // the session metadata can be accessed by notification listeners. This is done in this - // sample for convenience only. - return new MediaMetadata.Builder() - .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, id) - .putString(CUSTOM_METADATA_TRACK_SOURCE, source) - .putString(MediaMetadata.METADATA_KEY_ALBUM, album) - .putString(MediaMetadata.METADATA_KEY_ARTIST, artist) - .putLong(MediaMetadata.METADATA_KEY_DURATION, duration) - .putString(MediaMetadata.METADATA_KEY_GENRE, genre) - .putString(MediaMetadata.METADATA_KEY_ALBUM_ART_URI, iconUrl) - .putString(MediaMetadata.METADATA_KEY_TITLE, title) - .putLong(MediaMetadata.METADATA_KEY_TRACK_NUMBER, trackNumber) - .putLong(MediaMetadata.METADATA_KEY_NUM_TRACKS, totalTrackCount) - .build(); - } - - /** - * Download a JSON file from a server, parse the content and return the JSON - * object. - * - * @param urlString - * @return - */ - private JSONObject parseUrl(String urlString) { - InputStream is = null; - try { - java.net.URL url = new java.net.URL(urlString); - URLConnection urlConnection = url.openConnection(); - is = new BufferedInputStream(urlConnection.getInputStream()); - BufferedReader reader = new BufferedReader(new InputStreamReader( - urlConnection.getInputStream(), "iso-8859-1"), 8); - StringBuilder sb = new StringBuilder(); - String line = null; - while ((line = reader.readLine()) != null) { - sb.append(line); - } - return new JSONObject(sb.toString()); - } catch (Exception e) { - LogHelper.e(TAG, "Failed to parse the json for media list", e); - return null; - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - // ignore - } - } - } - } -}
\ No newline at end of file |