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      */
getMedia()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      */
retreiveMedia()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      */
parseUrl(String urlString)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 
getRootContainerCurser()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 
getRootItemCursor(int type)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