diff options
author | Nicole Borrelli <borrelli@google.com> | 2017-02-28 14:14:58 -0800 |
---|---|---|
committer | Nicole Borrelli <borrelli@google.com> | 2017-05-04 14:10:27 -0700 |
commit | 2f144e3d4d6cc18b79f79a962aa8cd790d74b412 (patch) | |
tree | aa32def7148d626aa54c13f2390ea5d0b5e025bc /media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java | |
parent | 83a1ddaa52c27e8edefe93a68b91c7e26668d0e4 (diff) | |
download | android-2f144e3d4d6cc18b79f79a962aa8cd790d74b412.tar.gz |
Vastly simplify the MediaBrowserService sample.
Bug: 37631425
Test: Existing tests pass. Manually verified.
Change-Id: Id7f86295e1c8d7372b4f79b3e511a736190792bf
Diffstat (limited to 'media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java')
-rw-r--r-- | media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java | 208 |
1 files changed, 69 insertions, 139 deletions
diff --git a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java index 949b0bdc..7eead436 100644 --- a/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java +++ b/media/MediaBrowserService/Application/src/main/java/com/example/android/mediabrowserservice/model/MusicProvider.java @@ -16,11 +16,9 @@ package com.example.android.mediabrowserservice.model; -import android.media.MediaMetadata; import android.os.AsyncTask; import android.support.v4.media.MediaMetadataCompat; - -import com.example.android.mediabrowserservice.utils.LogHelper; +import android.util.Log; import org.json.JSONArray; import org.json.JSONException; @@ -33,26 +31,26 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.LinkedHashMap; /** * Utility class to get a list of MusicTrack's based on a server-side JSON * configuration. + * + * In a real application this class may pull data from a remote server, as we do here, + * or potentially use {@link android.provider.MediaStore} to locate media files located on + * the device. */ public class MusicProvider { - private static final String TAG = LogHelper.makeLogTag(MusicProvider.class); + private static final String TAG = MusicProvider.class.getSimpleName(); - private static final String CATALOG_URL = - "http://storage.googleapis.com/automotive-media/music.json"; + public static final String MEDIA_ID_ROOT = "__ROOT__"; + public static final String MEDIA_ID_EMPTY_ROOT = "__EMPTY__"; - public static final String CUSTOM_METADATA_TRACK_SOURCE = "__SOURCE__"; + private static final String CATALOG_URL = + "https://storage.googleapis.com/automotive-media/music.json"; private static final String JSON_MUSIC = "music"; private static final String JSON_TITLE = "title"; @@ -66,108 +64,54 @@ public class MusicProvider { private static final String JSON_DURATION = "duration"; // Categorized caches for music track data: - private ConcurrentMap<String, List<MediaMetadata>> mMusicListByGenre; - private final ConcurrentMap<String, MutableMediaMetadata> mMusicListById; - - private final Set<String> mFavoriteTracks; + private final LinkedHashMap<String, MediaMetadataCompat> mMusicListById; - enum State { + private enum State { NON_INITIALIZED, INITIALIZING, INITIALIZED } private volatile State mCurrentState = State.NON_INITIALIZED; + /** + * Callback used by MusicService. + */ public interface Callback { void onMusicCatalogReady(boolean success); } public MusicProvider() { - mMusicListByGenre = new ConcurrentHashMap<>(); - mMusicListById = new ConcurrentHashMap<>(); - mFavoriteTracks = Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>()); + mMusicListById = new LinkedHashMap<>(); } - /** - * Get an iterator over the list of genres - * - * @return genres - */ - public Iterable<String> getGenres() { - if (mCurrentState != State.INITIALIZED) { + public Iterable<MediaMetadataCompat> getAllMusics() { + if (mCurrentState != State.INITIALIZED || mMusicListById.isEmpty()) { return Collections.emptyList(); } - return mMusicListByGenre.keySet(); + return mMusicListById.values(); } /** - * Get music tracks of the given genre - * - */ - public Iterable<MediaMetadata> getMusicsByGenre(String genre) { - if (mCurrentState != State.INITIALIZED || !mMusicListByGenre.containsKey(genre)) { - return Collections.emptyList(); - } - return mMusicListByGenre.get(genre); - } - - /** - * Very basic implementation of a search that filter music tracks which title containing - * the given query. + * Return the MediaMetadata for the given musicID. * + * @param musicId The unique music ID. */ - public Iterable<MediaMetadata> searchMusic(String titleQuery) { - if (mCurrentState != State.INITIALIZED) { - return Collections.emptyList(); - } - ArrayList<MediaMetadata> result = new ArrayList<>(); - titleQuery = titleQuery.toLowerCase(Locale.US); - for (MutableMediaMetadata track : mMusicListById.values()) { - if (track.metadata.getString(MediaMetadata.METADATA_KEY_TITLE).toLowerCase(Locale.US) - .contains(titleQuery)) { - result.add(track.metadata); - } - } - return result; + public MediaMetadataCompat getMusic(String musicId) { + return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId) : null; } /** - * Return the MediaMetadata for the given musicID. - * - * @param musicId The unique, non-hierarchical music ID. + * Update the metadata associated with a musicId. If the musicId doesn't exist, the + * update is dropped. (That is, it does not create a new mediaId.) + * @param musicId The ID + * @param metadata New Metadata to associate with it */ - public MediaMetadata getMusic(String musicId) { - return mMusicListById.containsKey(musicId) ? mMusicListById.get(musicId).metadata : null; - } - - public synchronized void updateMusic(String musicId, MediaMetadata metadata) { - MutableMediaMetadata track = mMusicListById.get(musicId); - if (track == null) { - return; - } - - String oldGenre = track.metadata.getString(MediaMetadata.METADATA_KEY_GENRE); - String newGenre = metadata.getString(MediaMetadata.METADATA_KEY_GENRE); - - track.metadata = metadata; - - // if genre has changed, we need to rebuild the list by genre - if (!oldGenre.equals(newGenre)) { - buildListsByGenre(); + public synchronized void updateMusic(String musicId, MediaMetadataCompat metadata) { + MediaMetadataCompat track = mMusicListById.get(musicId); + if (track != null) { + mMusicListById.put(musicId, metadata); } } - public void setFavorite(String musicId, boolean favorite) { - if (favorite) { - mFavoriteTracks.add(musicId); - } else { - mFavoriteTracks.remove(musicId); - } - } - - public boolean isFavorite(String musicId) { - return mFavoriteTracks.contains(musicId); - } - public boolean isInitialized() { return mCurrentState == State.INITIALIZED; } @@ -177,9 +121,9 @@ public class MusicProvider { * for future reference, keying tracks by musicId and grouping by genre. */ public void retrieveMediaAsync(final Callback callback) { - LogHelper.d(TAG, "retrieveMediaAsync called"); + Log.d(TAG, "retrieveMediaAsync called"); if (mCurrentState == State.INITIALIZED) { - // Nothing to do, execute callback immediately + // Already initialized, so call back immediately. callback.onMusicCatalogReady(true); return; } @@ -201,21 +145,6 @@ public class MusicProvider { }.execute(); } - private synchronized void buildListsByGenre() { - ConcurrentMap<String, List<MediaMetadata>> newMusicListByGenre = new ConcurrentHashMap<>(); - - for (MutableMediaMetadata m : mMusicListById.values()) { - String genre = m.metadata.getString(MediaMetadata.METADATA_KEY_GENRE); - List<MediaMetadata> list = newMusicListByGenre.get(genre); - if (list == null) { - list = new ArrayList<>(); - newMusicListByGenre.put(genre, list); - } - list.add(m.metadata); - } - mMusicListByGenre = newMusicListByGenre; - } - private synchronized void retrieveMedia() { try { if (mCurrentState == State.NON_INITIALIZED) { @@ -229,17 +158,16 @@ public class MusicProvider { } 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 musicId = item.getString(MediaMetadata.METADATA_KEY_MEDIA_ID); - mMusicListById.put(musicId, new MutableMediaMetadata(musicId, item)); + for (int j = tracks.length() - 1; j >= 0; j--) { + MediaMetadataCompat item = buildFromJSON(tracks.getJSONObject(j), path); + String musicId = item.getString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID); + mMusicListById.put(musicId, item); } - buildListsByGenre(); } mCurrentState = State.INITIALIZED; } - } catch (JSONException e) { - LogHelper.e(TAG, e, "Could not retrieve music list"); + } catch (JSONException jsonException) { + Log.e(TAG, "Could not retrieve music list", jsonException); } finally { if (mCurrentState != State.INITIALIZED) { // Something bad happened, so we reset state to NON_INITIALIZED to allow @@ -249,7 +177,9 @@ public class MusicProvider { } } - private MediaMetadata buildFromJSON(JSONObject json, String basePath) throws JSONException { + private MediaMetadataCompat 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); @@ -260,13 +190,13 @@ public class MusicProvider { int totalTrackCount = json.getInt(JSON_TOTAL_TRACK_COUNT); int duration = json.getInt(JSON_DURATION) * 1000; // ms - LogHelper.d(TAG, "Found music track: ", json); + Log.d(TAG, "Found music track: " + json); // Media is stored relative to JSON file - if (!source.startsWith("http")) { + if (!source.startsWith("https")) { source = basePath + source; } - if (!iconUrl.startsWith("http")) { + if (!iconUrl.startsWith("https")) { iconUrl = basePath + iconUrl; } // Since we don't have a unique ID in the server, we fake one using the hashcode of @@ -277,18 +207,17 @@ public class MusicProvider { // 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. - //noinspection WrongConstant - 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) + return new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id) + .putString(MediaMetadataCompat.METADATA_KEY_MEDIA_URI, source) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, album) + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) + .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration) + .putString(MediaMetadataCompat.METADATA_KEY_GENRE, genre) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, iconUrl) + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) + .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, trackNumber) + .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, totalTrackCount) .build(); } @@ -299,28 +228,29 @@ public class MusicProvider { * @return result JSONObject containing the parsed representation. */ private JSONObject fetchJSONFromUrl(String urlString) { - InputStream is = null; + InputStream inputStream = null; try { URL url = new URL(urlString); URLConnection urlConnection = url.openConnection(); - is = new BufferedInputStream(urlConnection.getInputStream()); + inputStream = new BufferedInputStream(urlConnection.getInputStream()); BufferedReader reader = new BufferedReader(new InputStreamReader( urlConnection.getInputStream(), "iso-8859-1")); - StringBuilder sb = new StringBuilder(); + StringBuilder stringBuilder = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { - sb.append(line); + stringBuilder.append(line); } - return new JSONObject(sb.toString()); - } catch (Exception e) { - LogHelper.e(TAG, "Failed to parse the json for media list", e); + return new JSONObject(stringBuilder.toString()); + } catch (IOException | JSONException exception) { + Log.e(TAG, "Failed to parse the json for media list", exception); return null; } finally { - if (is != null) { + // If the inputStream was opened, try to close it now. + if (inputStream != null) { try { - is.close(); - } catch (IOException e) { - // ignore + inputStream.close(); + } catch (IOException ignored) { + // Ignore the exception since there's nothing left to do with the stream } } } |