1 /* 2 * Copyright (C) 2014 Google Inc. All Rights Reserved. 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.example.android.musicservicedemo.browser; 18 19 import android.database.MatrixCursor; 20 import android.media.session.PlaybackState; 21 import android.net.Uri; 22 import android.util.Log; 23 24 import com.example.android.musicservicedemo.BrowserService; 25 26 import org.json.JSONArray; 27 import org.json.JSONException; 28 import org.json.JSONObject; 29 30 import java.io.BufferedInputStream; 31 import java.io.BufferedReader; 32 import java.io.IOException; 33 import java.io.InputStream; 34 import java.io.InputStreamReader; 35 import java.net.URLConnection; 36 import java.util.ArrayList; 37 import java.util.List; 38 39 /** 40 * Utility class to get a list of MusicTrack's based on a server-side JSON 41 * configuration. 42 */ 43 public class MusicProvider { 44 45 private static final String TAG = "MusicProvider"; 46 47 private static final String MUSIC_URL = "http://storage.googleapis.com/automotive-media/music.json"; 48 49 private static String MUSIC = "music"; 50 private static String TITLE = "title"; 51 private static String ALBUM = "album"; 52 private static String ARTIST = "artist"; 53 private static String GENRE = "genre"; 54 private static String SOURCE = "source"; 55 private static String IMAGE = "image"; 56 private static String TRACK_NUMBER = "trackNumber"; 57 private static String TOTAL_TRACK_COUNT = "totalTrackCount"; 58 private static String DURATION = "duration"; 59 60 // Cache for music track data 61 private static List<MusicTrack> mMusicList; 62 63 /** 64 * Get the cached list of music tracks 65 * 66 * @return 67 * @throws JSONException 68 */ 69 public List<MusicTrack> getMedia() throws JSONException { 70 if (null != mMusicList && mMusicList.size() > 0) { 71 return mMusicList; 72 } 73 return null; 74 } 75 76 /** 77 * Get the list of music tracks from a server and return the list of 78 * MusicTrack objects. 79 * 80 * @return 81 * @throws JSONException 82 */ 83 public List<MusicTrack> retreiveMedia() throws JSONException { 84 if (null != mMusicList) { 85 return mMusicList; 86 } 87 int slashPos = MUSIC_URL.lastIndexOf('/'); 88 String path = MUSIC_URL.substring(0, slashPos + 1); 89 JSONObject jsonObj = parseUrl(MUSIC_URL); 90 91 try { 92 JSONArray videos = jsonObj.getJSONArray(MUSIC); 93 if (null != videos) { 94 mMusicList = new ArrayList<MusicTrack>(); 95 for (int j = 0; j < videos.length(); j++) { 96 JSONObject music = videos.getJSONObject(j); 97 String title = music.getString(TITLE); 98 String album = music.getString(ALBUM); 99 String artist = music.getString(ARTIST); 100 String genre = music.getString(GENRE); 101 String source = music.getString(SOURCE); 102 // Media is stored relative to JSON file 103 if (!source.startsWith("http")) { 104 source = path + source; 105 } 106 String image = music.getString(IMAGE); 107 if (!image.startsWith("http")) { 108 image = path + image; 109 } 110 int trackNumber = music.getInt(TRACK_NUMBER); 111 int totalTrackCount = music.getInt(TOTAL_TRACK_COUNT); 112 int duration = music.getInt(DURATION) * 1000; // ms 113 114 mMusicList.add(new MusicTrack(title, album, artist, genre, source, 115 image, trackNumber, totalTrackCount, duration)); 116 } 117 } 118 } catch (NullPointerException e) { 119 Log.e(TAG, "retreiveMedia", e); 120 } 121 return mMusicList; 122 } 123 124 /** 125 * Download a JSON file from a server, parse the content and return the JSON 126 * object. 127 * 128 * @param urlString 129 * @return 130 */ 131 private JSONObject parseUrl(String urlString) { 132 InputStream is = null; 133 try { 134 java.net.URL url = new java.net.URL(urlString); 135 URLConnection urlConnection = url.openConnection(); 136 is = new BufferedInputStream(urlConnection.getInputStream()); 137 BufferedReader reader = new BufferedReader(new InputStreamReader( 138 urlConnection.getInputStream(), "iso-8859-1"), 8); 139 StringBuilder sb = new StringBuilder(); 140 String line = null; 141 while ((line = reader.readLine()) != null) { 142 sb.append(line); 143 } 144 return new JSONObject(sb.toString()); 145 } catch (Exception e) { 146 Log.d(TAG, "Failed to parse the json for media list", e); 147 return null; 148 } finally { 149 if (null != is) { 150 try { 151 is.close(); 152 } catch (IOException e) { 153 // ignore 154 } 155 } 156 } 157 } 158 159 public MatrixCursor getRootContainerCurser() { 160 MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); 161 Uri.Builder pianoBuilder = new Uri.Builder(); 162 pianoBuilder.authority(BrowserService.AUTHORITY); 163 pianoBuilder.appendPath(BrowserService.PIANO_BASE_PATH); 164 matrixCursor.addRow(new Object[] { 165 pianoBuilder.build(), 166 BrowserService.PIANO_BASE_PATH, 167 "subtitle", 168 null, 169 0 170 }); 171 172 Uri.Builder voiceBuilder = new Uri.Builder(); 173 voiceBuilder.authority(BrowserService.AUTHORITY); 174 voiceBuilder.appendPath(BrowserService.VOICE_BASE_PATH); 175 matrixCursor.addRow(new Object[] { 176 voiceBuilder.build(), 177 BrowserService.VOICE_BASE_PATH, 178 "subtitle", 179 null, 180 0 181 }); 182 return matrixCursor; 183 } 184 185 public MatrixCursor getRootItemCursor(int type) { 186 if (type == BrowserService.NOW_PLAYING) { 187 MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); 188 189 try { 190 // Just return all of the tracks for now 191 List<MusicTrack> musicTracks = retreiveMedia(); 192 for (MusicTrack musicTrack : musicTracks) { 193 Uri.Builder builder = new Uri.Builder(); 194 builder.authority(BrowserService.AUTHORITY); 195 builder.appendPath(BrowserService.NOW_PLAYING_PATH); 196 builder.appendPath(musicTrack.getTitle()); 197 matrixCursor.addRow(new Object[] { 198 builder.build(), 199 musicTrack.getTitle(), 200 musicTrack.getArtist(), 201 musicTrack.getImage(), 202 PlaybackState.ACTION_PLAY 203 }); 204 Log.d(TAG, "Uri " + builder.build()); 205 } 206 } catch (JSONException e) { 207 Log.e(TAG, "::getRootItemCursor:", e); 208 } 209 210 Log.d(TAG, "cursor: " + matrixCursor.getCount()); 211 return matrixCursor; 212 } else if (type == BrowserService.PIANO) { 213 MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); 214 215 try { 216 List<MusicTrack> musicTracks = retreiveMedia(); 217 for (MusicTrack musicTrack : musicTracks) { 218 Uri.Builder builder = new Uri.Builder(); 219 builder.authority(BrowserService.AUTHORITY); 220 builder.appendPath(BrowserService.PIANO_BASE_PATH); 221 builder.appendPath(musicTrack.getTitle()); 222 matrixCursor.addRow(new Object[] { 223 builder.build(), 224 musicTrack.getTitle(), 225 musicTrack.getArtist(), 226 musicTrack.getImage(), 227 PlaybackState.ACTION_PLAY 228 }); 229 Log.d(TAG, "Uri " + builder.build()); 230 } 231 } catch (JSONException e) { 232 Log.e(TAG, "::getRootItemCursor:", e); 233 } 234 235 Log.d(TAG, "cursor: " + matrixCursor.getCount()); 236 return matrixCursor; 237 } else if (type == BrowserService.VOICE) { 238 MatrixCursor matrixCursor = new MatrixCursor(BrowserService.MEDIA_CONTAINER_PROJECTION); 239 240 try { 241 List<MusicTrack> musicTracks = retreiveMedia(); 242 for (MusicTrack musicTrack : musicTracks) { 243 Uri.Builder builder = new Uri.Builder(); 244 builder.authority(BrowserService.AUTHORITY); 245 builder.appendPath(BrowserService.VOICE_BASE_PATH); 246 builder.appendPath(musicTrack.getTitle()); 247 matrixCursor.addRow(new Object[] { 248 builder.build(), 249 musicTrack.getTitle(), 250 musicTrack.getArtist(), 251 musicTrack.getImage(), 252 PlaybackState.ACTION_PLAY 253 }); 254 Log.d(TAG, "Uri " + builder.build()); 255 } 256 } catch (JSONException e) { 257 Log.e(TAG, "::getRootItemCursor:", e); 258 } 259 260 Log.d(TAG, "cursor: " + matrixCursor.getCount()); 261 return matrixCursor; 262 263 } 264 return null; 265 } 266 } 267