Merge lp:~ubuntuone-client-engineering/ubuntuone-android-music/metadata-caching-optimisation into lp:ubuntuone-android-music/v2
- metadata-caching-optimisation
- Merge into v2
Proposed by
Michał Karnicki
Status: | Merged |
---|---|
Merged at revision: | 26 |
Proposed branch: | lp:~ubuntuone-client-engineering/ubuntuone-android-music/metadata-caching-optimisation |
Merge into: | lp:ubuntuone-android-music/v2 |
Diff against target: |
2137 lines (+1333/-185) 19 files modified
src/com/ubuntuone/android/music/UbuntuOneMusic.java (+13/-4) src/com/ubuntuone/android/music/provider/MusicContentValues.java (+22/-13) src/com/ubuntuone/android/music/provider/MusicContract.java (+1/-1) src/com/ubuntuone/android/music/provider/MusicDatabase.java (+3/-3) src/com/ubuntuone/android/music/provider/MusicProvider.java (+1/-1) src/com/ubuntuone/android/music/provider/MusicProviderUtils.java (+3/-3) src/com/ubuntuone/android/music/provider/dao/AlbumDao.java (+130/-0) src/com/ubuntuone/android/music/provider/dao/ArtistDao.java (+170/-0) src/com/ubuntuone/android/music/provider/dao/Dao.java (+76/-0) src/com/ubuntuone/android/music/provider/dao/GenreDao.java (+86/-0) src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java (+109/-0) src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java (+97/-0) src/com/ubuntuone/android/music/provider/dao/SongDao.java (+194/-0) src/com/ubuntuone/android/music/service/MusicService.java (+2/-2) src/com/ubuntuone/android/music/service/SyncService.java (+136/-78) src/com/ubuntuone/android/music/ui/HomeActivity.java (+1/-1) test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java (+10/-0) test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java (+8/-8) test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java (+271/-71) |
To merge this branch: | bzr merge lp:~ubuntuone-client-engineering/ubuntuone-android-music/metadata-caching-optimisation |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Roberto Alsina (community) | code review | Approve | |
Review via email: mp+135477@code.launchpad.net |
Commit message
Metadata caching speed optimization.
Description of the change
Metadata caching speed optimization (talking directly to SQLite db in SyncService, instead of talking through content provider abstraction layer). With tests. And some minor test clean-up.
To post a comment you must log in.
Revision history for this message
Roberto Alsina (ralsina) : | # |
review:
Approve
(code review)
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'src/com/ubuntuone/android/music/UbuntuOneMusic.java' |
2 | --- src/com/ubuntuone/android/music/UbuntuOneMusic.java 2012-11-13 13:58:31 +0000 |
3 | +++ src/com/ubuntuone/android/music/UbuntuOneMusic.java 2012-11-21 17:34:22 +0000 |
4 | @@ -45,11 +45,20 @@ |
5 | { |
6 | public static final String TAG = UbuntuOneMusic.class.getSimpleName(); |
7 | |
8 | - public static final boolean DEBUG_SHOULD_SYNC = true; |
9 | - public static final boolean DEBUG_SHOULD_BIND = true; |
10 | - public static final boolean DEBUG_SHOULD_PLAY = true; |
11 | + /** Should always be true. False would indicate a debug build. */ |
12 | + public static final boolean IS_RELEASE = true; // Never commit false. |
13 | + |
14 | + // Following flags have been introduced to ease proper test suite runs and debugging. |
15 | + |
16 | + /** Debug flag indicating if the app should attempt metadata sync. */ |
17 | + public static final boolean SHOULD_SYNC = IS_RELEASE; |
18 | + /** Debug flag indicating if the app should bind to {@link MusicService}. */ |
19 | + public static final boolean SHOULD_BIND = IS_RELEASE; |
20 | + /** Debug flag indicating if the app should actually playback music. */ |
21 | + public static final boolean SHOULD_PLAY = IS_RELEASE; |
22 | + |
23 | // Set this to true to enable foreign key constraint enforcing. |
24 | - public static final boolean DEBUG_SHOULD_USE_FK = false; |
25 | + public static final boolean SHOULD_USE_FK = true; |
26 | |
27 | private static UbuntuOneMusic instance; |
28 | private U1MusicAPI mApi; |
29 | |
30 | === modified file 'src/com/ubuntuone/android/music/provider/MusicContentValues.java' |
31 | --- src/com/ubuntuone/android/music/provider/MusicContentValues.java 2012-11-13 13:58:31 +0000 |
32 | +++ src/com/ubuntuone/android/music/provider/MusicContentValues.java 2012-11-21 17:34:22 +0000 |
33 | @@ -25,6 +25,7 @@ |
34 | |
35 | import java.util.ArrayList; |
36 | import java.util.Iterator; |
37 | +import java.util.Locale; |
38 | import java.util.Map.Entry; |
39 | import java.util.Random; |
40 | import java.util.Set; |
41 | @@ -52,12 +53,16 @@ |
42 | |
43 | private static final boolean PRINT_CONTENT_VALUES = false; |
44 | |
45 | - public static ContentValues from(U1Artist artist) { |
46 | + public static String getAlbumList(U1Artist artist) { |
47 | + return StringUtils.join(artist.getAlbumIds(), ","); |
48 | + } |
49 | + |
50 | + public static ContentValues forArtist(U1Artist artist) { |
51 | final ContentValues cv = new ContentValues(); |
52 | cv.put(Artists.UPDATED, System.currentTimeMillis()); |
53 | cv.put(Artists.ARTIST_ID, artist.getId()); |
54 | cv.put(Artists.ARTIST_NAME, artist.getArtist()); |
55 | - cv.put(Artists.ALBUM_LIST, StringUtils.join(artist.getAlbumIds(), ",")); |
56 | + cv.put(Artists.ALBUM_LIST, getAlbumList(artist)); |
57 | cv.put(Artists.ALBUM_COUNT, artist.getAlbumIds().size()); |
58 | cv.put(Artists.SONG_COUNT, artist.getSongCount()); |
59 | cv.put(Artists.ARTIST_URL, artist.getArtistUrl()); |
60 | @@ -66,7 +71,7 @@ |
61 | return cv; |
62 | } |
63 | |
64 | - public static ArrayList<ContentValues> albumsFrom(U1Artist artist) { |
65 | + public static ArrayList<ContentValues> forArtistAlbums(U1Artist artist) { |
66 | ArrayList<ContentValues> values = new ArrayList<ContentValues>(); |
67 | ArrayList<String> albumIds = artist.getAlbumIds(); |
68 | for (String albumId : albumIds) { |
69 | @@ -80,13 +85,13 @@ |
70 | return values; |
71 | } |
72 | |
73 | - public static ContentValues from(U1Album album) { |
74 | + public static ContentValues forAlbum(U1Album album) { |
75 | final ContentValues cv = new ContentValues(); |
76 | cv.put(Albums.UPDATED, System.currentTimeMillis()); |
77 | cv.put(Albums.ALBUM_ID, album.getId()); |
78 | cv.put(Albums.ALBUM_TITLE, album.getTitle()); |
79 | cv.put(Albums.ALBUM_ARTIST, album.getArtist()); |
80 | - cv.put(Albums.ALBUM_ARTIST_ID, HashUtils.md5(album.getArtist())); |
81 | + cv.put(Albums.ALBUM_ARTIST_ID, album.getArtistId()); |
82 | cv.put(Albums.ALBUM_YEAR, album.getYear()); |
83 | cv.put(Albums.ALBUM_DATE_ADDED, album.getParsedDate()); |
84 | cv.put(Albums.ALBUM_URL, album.getAlbumUrl()); |
85 | @@ -95,7 +100,7 @@ |
86 | return cv; |
87 | } |
88 | |
89 | - public static ContentValues from(U1Song song) { |
90 | + public static ContentValues forSong(U1Song song) { |
91 | final ContentValues cv = new ContentValues(); |
92 | cv.put(Songs.UPDATED, System.currentTimeMillis()); |
93 | cv.put(Songs.SONG_ID, song.getId()); |
94 | @@ -104,10 +109,10 @@ |
95 | cv.put(Songs.SONG_ALBUM_ID, song.getAlbumId()); |
96 | cv.put(Songs.SONG_ALBUM_ARTIST, song.getAlbumArtist()); |
97 | cv.put(Songs.SONG_ARTIST, song.getArtist()); |
98 | - cv.put(Songs.SONG_ARTIST_ID, HashUtils.md5(song.getArtist())); |
99 | + cv.put(Songs.SONG_ARTIST_ID, song.getArtistId()); |
100 | cv.put(Songs.SONG_GENRE, song.getGenre()); |
101 | // TODO Calculate /0 separated genre md5 sums maybe? |
102 | - cv.put(Songs.SONG_GENRE_ID, HashUtils.md5(song.getGenre().toUpperCase())); |
103 | + cv.put(Songs.SONG_GENRE_ID, getGenreId(song.getGenre())); |
104 | cv.put(Songs.SONG_YEAR, song.getYear()); |
105 | cv.put(Songs.SONG_DISC_NUMBER, song.getDiscNumber()); |
106 | cv.put(Songs.SONG_TRACK, song.getTrack()); |
107 | @@ -125,7 +130,7 @@ |
108 | return cv; |
109 | } |
110 | |
111 | - public static ContentValues from(U1Playlist playlist) { |
112 | + public static ContentValues forPlaylist(U1Playlist playlist) { |
113 | final ContentValues cv = new ContentValues(); |
114 | cv.put(Playlists.UPDATED, System.currentTimeMillis()); |
115 | cv.put(Playlists.PLAYLIST_ID, playlist.getId()); |
116 | @@ -136,7 +141,7 @@ |
117 | return cv; |
118 | } |
119 | |
120 | - public static ContentValues from(String playlistId, String songId) { |
121 | + public static ContentValues forPlaylistSong(String playlistId, String songId) { |
122 | final ContentValues cv = new ContentValues(); |
123 | cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis()); |
124 | cv.put(PlaylistSongs.PLAYLIST_ID, playlistId); |
125 | @@ -145,7 +150,7 @@ |
126 | return cv; |
127 | } |
128 | |
129 | - public static ContentValues from(Random random) { |
130 | + public static ContentValues forShuffleOrder(Random random) { |
131 | final ContentValues cv = new ContentValues(); |
132 | cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis()); |
133 | cv.put(PlaylistSongs.SHUFFLE_ORDER, random.nextLong()); |
134 | @@ -153,10 +158,14 @@ |
135 | return cv; |
136 | } |
137 | |
138 | - public static ContentValues fromGenre(String genre) { |
139 | + public static String getGenreId(String genre) { |
140 | + return HashUtils.md5(genre.toLowerCase(Locale.US)); |
141 | + } |
142 | + |
143 | + public static ContentValues forGenre(String genre) { |
144 | final ContentValues cv = new ContentValues(); |
145 | cv.put(Genres.UPDATED, System.currentTimeMillis()); |
146 | - cv.put(Genres.GENRE_ID, HashUtils.md5(genre.toUpperCase())); |
147 | + cv.put(Genres.GENRE_ID, getGenreId(genre)); |
148 | cv.put(Genres.GENRE_TITLE, genre); |
149 | return cv; |
150 | } |
151 | |
152 | === modified file 'src/com/ubuntuone/android/music/provider/MusicContract.java' |
153 | --- src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-08 14:14:54 +0000 |
154 | +++ src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-21 17:34:22 +0000 |
155 | @@ -273,7 +273,7 @@ |
156 | } |
157 | } |
158 | |
159 | - /* package */ static class ArtistAlbums implements ArtistAlbumsColumns, SyncColumns, |
160 | + public static class ArtistAlbums implements ArtistAlbumsColumns, SyncColumns, |
161 | SongsColumns, BaseColumns |
162 | { |
163 | public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon() |
164 | |
165 | === modified file 'src/com/ubuntuone/android/music/provider/MusicDatabase.java' |
166 | --- src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-13 13:58:31 +0000 |
167 | +++ src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-21 17:34:22 +0000 |
168 | @@ -61,7 +61,7 @@ |
169 | |
170 | //private static final String NOW = "strftime('%s', 'now')"; |
171 | |
172 | - interface Tables |
173 | + public interface Tables |
174 | { |
175 | String ARTISTS = "artists"; |
176 | String ARTISTS_ALBUMS = "artists_albums"; |
177 | @@ -115,7 +115,7 @@ |
178 | @Override |
179 | public SQLiteDatabase getWritableDatabase() { |
180 | SQLiteDatabase db = super.getWritableDatabase(); |
181 | - if (UbuntuOneMusic.DEBUG_SHOULD_USE_FK) { |
182 | + if (UbuntuOneMusic.SHOULD_USE_FK) { |
183 | db.execSQL("PRAGMA foreign_keys = ON"); |
184 | } |
185 | return db; |
186 | @@ -207,7 +207,7 @@ |
187 | // Create the play queue playlist. |
188 | U1Playlist queuePlaylist = new U1Playlist( |
189 | MusicProviderUtils.QUEUE_ID, "", MusicProviderUtils.QUEUE_NAME, 0); |
190 | - ContentValues values = MusicContentValues.from(queuePlaylist); |
191 | + ContentValues values = MusicContentValues.forPlaylist(queuePlaylist); |
192 | db.insert(Tables.PLAYLISTS, null, values); |
193 | |
194 | db.execSQL("CREATE TABLE " + Tables.PLAYLISTS_SONGS + "(" |
195 | |
196 | === modified file 'src/com/ubuntuone/android/music/provider/MusicProvider.java' |
197 | --- src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-08 14:14:54 +0000 |
198 | +++ src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-21 17:34:22 +0000 |
199 | @@ -325,7 +325,7 @@ |
200 | String lcGenre = genre != null ? genre.trim().toLowerCase() : ""; |
201 | if (!TextUtils.isEmpty(lcGenre) && !lcGenre.equals("null") && !lcGenre.equals("genre")) { |
202 | // XXX Do we want all genres uppercase? If so, toUpperCase() genre below. |
203 | - ContentValues genreValues = MusicContentValues.fromGenre(genre.trim()); |
204 | + ContentValues genreValues = MusicContentValues.forGenre(genre.trim()); |
205 | db.insertOrThrow(Tables.GENRES, null, genreValues); |
206 | } |
207 | } |
208 | |
209 | === modified file 'src/com/ubuntuone/android/music/provider/MusicProviderUtils.java' |
210 | --- src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-08 14:14:54 +0000 |
211 | +++ src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-21 17:34:22 +0000 |
212 | @@ -242,7 +242,7 @@ |
213 | String playlistId = Playlists.getPlaylistId(playlistUri); |
214 | String songId = Songs.getSongId(songUri); |
215 | |
216 | - ContentValues values = MusicContentValues.from(playlistId, songId); |
217 | + ContentValues values = MusicContentValues.forPlaylistSong(playlistId, songId); |
218 | resolver.insert(playlistUri, values); |
219 | } |
220 | |
221 | @@ -261,7 +261,7 @@ |
222 | if (cursor != null && cursor.isBeforeFirst()) { |
223 | while (cursor.moveToNext()) { |
224 | String songId = cursor.getString(cursor.getColumnIndex(Songs.SONG_ID)); |
225 | - ContentValues values = MusicContentValues.from( |
226 | + ContentValues values = MusicContentValues.forPlaylistSong( |
227 | MusicProviderUtils.QUEUE_ID, songId); |
228 | resolver.insert(MusicProviderUtils.QUEUE_URI, values); |
229 | } |
230 | @@ -650,7 +650,7 @@ |
231 | String playlistId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.PLAYLIST_ID)); |
232 | String songId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.SONG_ID)); |
233 | Uri queueSongUri = Playlists.buildPlaylistSongUri(playlistId, songId); |
234 | - ContentValues values = MusicContentValues.from(random); |
235 | + ContentValues values = MusicContentValues.forShuffleOrder(random); |
236 | |
237 | resolver.update(queueSongUri, values, null, null); |
238 | } |
239 | |
240 | === added directory 'src/com/ubuntuone/android/music/provider/dao' |
241 | === added file 'src/com/ubuntuone/android/music/provider/dao/AlbumDao.java' |
242 | --- src/com/ubuntuone/android/music/provider/dao/AlbumDao.java 1970-01-01 00:00:00 +0000 |
243 | +++ src/com/ubuntuone/android/music/provider/dao/AlbumDao.java 2012-11-21 17:34:22 +0000 |
244 | @@ -0,0 +1,130 @@ |
245 | +package com.ubuntuone.android.music.provider.dao; |
246 | + |
247 | +import android.content.ContentResolver; |
248 | +import android.content.ContentValues; |
249 | +import android.database.sqlite.SQLiteDatabase; |
250 | +import android.database.sqlite.SQLiteStatement; |
251 | +import android.net.Uri; |
252 | + |
253 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
254 | +import com.ubuntuone.android.music.provider.MusicContract.Albums; |
255 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
256 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
257 | +import com.ubuntuone.android.music.provider.MusicProvider; |
258 | +import com.ubuntuone.api.music.model.U1Album; |
259 | + |
260 | +public class AlbumDao extends Dao |
261 | +{ |
262 | + public AlbumDao() { |
263 | + } |
264 | + |
265 | + /** |
266 | + * Updates the album. If the album doesn't exist, inserts the album. |
267 | + * Backed by {@link MusicProvider}. |
268 | + * |
269 | + * @param resolver |
270 | + * The content resolver. |
271 | + * @param artist |
272 | + * The {@link U1Album} to save. |
273 | + */ |
274 | + public void updateOrInsert(ContentResolver resolver, U1Album album) { |
275 | + ContentValues values = MusicContentValues.forAlbum(album); |
276 | + Uri albumUri = Albums.buildAlbumUri(album.getId()); |
277 | + int count = resolver.update(albumUri, values, null, null); |
278 | + if (count == 0) { |
279 | + resolver.insert(Albums.CONTENT_URI, values); |
280 | + } |
281 | + } |
282 | + |
283 | + /** |
284 | + * Updates the album. If the album doesn't exist, inserts the album. |
285 | + * Backed by {@link MusicDatabase}. |
286 | + * |
287 | + * @param db |
288 | + * The {@link MusicDatabase} instance. |
289 | + * @param artist |
290 | + * The {@link U1Album} to save. |
291 | + * @return True if update or insert succeeded, false otherwise. |
292 | + */ |
293 | + public boolean updateOrInsert(SQLiteDatabase db, U1Album album) { |
294 | + boolean isSuccess = false; |
295 | + |
296 | + SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql()); |
297 | + int i = 1; // Index to the parameter to bind. |
298 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
299 | + |
300 | + sqlStmt.bindString(i++, album.getTitle()); |
301 | + sqlStmt.bindString(i++, album.getArtist()); |
302 | + sqlStmt.bindString(i++, album.getArtistId()); |
303 | + sqlStmt.bindLong(i++, album.getYear()); |
304 | + |
305 | + sqlStmt.bindLong(i++, album.getParsedDate()); |
306 | + sqlStmt.bindString(i++, album.getAlbumUrl()); |
307 | + sqlStmt.bindString(i++, album.getAlbumArtUrl()); |
308 | + |
309 | + sqlStmt.bindString(i++, album.getId()); |
310 | + // Can't use executeUpdateDelete on API < 11 |
311 | + sqlStmt.execute(); |
312 | + long rowsUpdated = getChanges(db); |
313 | + |
314 | + if (rowsUpdated == 0L) { |
315 | + sqlStmt = db.compileStatement(getInsertSql()); |
316 | + i = 1; |
317 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
318 | + sqlStmt.bindString(i++, album.getId()); |
319 | + |
320 | + sqlStmt.bindString(i++, album.getTitle()); |
321 | + sqlStmt.bindString(i++, album.getArtist()); |
322 | + sqlStmt.bindString(i++, album.getArtistId()); |
323 | + sqlStmt.bindLong(i++, album.getYear()); |
324 | + |
325 | + sqlStmt.bindLong(i++, album.getParsedDate()); |
326 | + sqlStmt.bindString(i++, album.getAlbumUrl()); |
327 | + sqlStmt.bindString(i++, album.getAlbumArtUrl()); |
328 | + |
329 | + long rowId = sqlStmt.executeInsert(); |
330 | + isSuccess = rowId != -1; |
331 | + } else { |
332 | + isSuccess = rowsUpdated == 1; |
333 | + } |
334 | + return isSuccess; |
335 | + } |
336 | + |
337 | + @Override |
338 | + public String onGetInsertSql() { |
339 | + return "INSERT INTO " + Tables.ALBUMS + "(" + |
340 | + Albums.UPDATED + ", " + |
341 | + Albums.ALBUM_ID + ", " + |
342 | + |
343 | + Albums.ALBUM_TITLE + ", " + |
344 | + Albums.ALBUM_ARTIST + ", " + |
345 | + Albums.ALBUM_ARTIST_ID + ", " + |
346 | + Albums.ALBUM_YEAR + ", " + |
347 | + |
348 | + Albums.ALBUM_DATE_ADDED + ", " + |
349 | + Albums.ALBUM_URL + ", " + |
350 | + Albums.ALBUM_ART_URL + |
351 | + |
352 | + ") VALUES (?, ?, " + |
353 | + "?, ?, ?, ?, " + |
354 | + "?, ?, ?" + |
355 | + ")"; |
356 | + } |
357 | + |
358 | + @Override |
359 | + public String onGetUpdateSql() { |
360 | + return "UPDATE " + Tables.ALBUMS + " SET " + |
361 | + Albums.UPDATED + "=?, " + |
362 | + |
363 | + Albums.ALBUM_TITLE + "=?, " + |
364 | + Albums.ALBUM_ARTIST + "=?, " + |
365 | + Albums.ALBUM_ARTIST_ID + "=?, " + |
366 | + Albums.ALBUM_YEAR + "=?, " + |
367 | + |
368 | + Albums.ALBUM_DATE_ADDED + "=?, " + |
369 | + Albums.ALBUM_URL + "=?, " + |
370 | + Albums.ALBUM_ART_URL + "=? " + |
371 | + |
372 | + "WHERE " + Albums.ALBUM_ID + "=?"; |
373 | + } |
374 | +} |
375 | |
376 | === added file 'src/com/ubuntuone/android/music/provider/dao/ArtistDao.java' |
377 | --- src/com/ubuntuone/android/music/provider/dao/ArtistDao.java 1970-01-01 00:00:00 +0000 |
378 | +++ src/com/ubuntuone/android/music/provider/dao/ArtistDao.java 2012-11-21 17:34:22 +0000 |
379 | @@ -0,0 +1,170 @@ |
380 | +package com.ubuntuone.android.music.provider.dao; |
381 | + |
382 | +import java.util.ArrayList; |
383 | + |
384 | +import android.content.ContentResolver; |
385 | +import android.content.ContentValues; |
386 | +import android.database.sqlite.SQLiteDatabase; |
387 | +import android.database.sqlite.SQLiteStatement; |
388 | +import android.net.Uri; |
389 | + |
390 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
391 | +import com.ubuntuone.android.music.provider.MusicContract.Albums; |
392 | +import com.ubuntuone.android.music.provider.MusicContract.ArtistAlbums; |
393 | +import com.ubuntuone.android.music.provider.MusicContract.Artists; |
394 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
395 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
396 | +import com.ubuntuone.android.music.provider.MusicProvider; |
397 | +import com.ubuntuone.android.music.util.StringUtils; |
398 | +import com.ubuntuone.api.music.model.U1Artist; |
399 | + |
400 | +public class ArtistDao extends Dao |
401 | +{ |
402 | + public ArtistDao() { |
403 | + } |
404 | + |
405 | + /** |
406 | + * Updates the artist. If the artist doesn't exist, inserts the artist. |
407 | + * Backed by {@link MusicProvider}. |
408 | + * |
409 | + * @param resolver |
410 | + * The content resolver. |
411 | + * @param artist |
412 | + * The {@link U1Artist} to save. |
413 | + */ |
414 | + public void updateOrInsert(ContentResolver resolver, U1Artist artist) { |
415 | + ContentValues values = MusicContentValues.forArtist(artist); |
416 | + Uri artistUri = Artists.buildArtistUri(artist.getId()); |
417 | + int count = resolver.update(artistUri, values, null, null); |
418 | + if (count == 0) { |
419 | + resolver.insert(Artists.CONTENT_URI, values); |
420 | + } |
421 | + // Insert artist albums. |
422 | + ArrayList<ContentValues> albumsValues = MusicContentValues.forArtistAlbums(artist); |
423 | + for (ContentValues albumValues : albumsValues) { |
424 | + Uri artistAlbumUri = Artists.buildAlbumUri( |
425 | + artist.getId(), albumValues.getAsString(Albums.ALBUM_ID)); |
426 | + int count2 = resolver.update(artistAlbumUri, albumValues, null, null); |
427 | + if (count2 == 0) { |
428 | + resolver.insert(artistAlbumUri, albumValues); |
429 | + } |
430 | + } |
431 | + } |
432 | + |
433 | + /** |
434 | + * Updates the artist. If the artist doesn't exist, inserts the artist. |
435 | + * Backed by {@link MusicDatabase}. |
436 | + * |
437 | + * @param db |
438 | + * The {@link MusicDatabase} instance. |
439 | + * @param artist |
440 | + * The {@link U1Artist} to save. |
441 | + * @return True if update or insert succeeded, false otherwise. |
442 | + */ |
443 | + public boolean updateOrInsert(SQLiteDatabase db, U1Artist artist) { |
444 | + boolean isSuccess = false; |
445 | + |
446 | + SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql()); |
447 | + int i = 1; // Index to the parameter to bind. |
448 | + |
449 | + final String albumList = StringUtils.join(artist.getAlbumIds(), ","); |
450 | + final long albumListSize = artist.getAlbumIds().size(); |
451 | + |
452 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
453 | + |
454 | + sqlStmt.bindString(i++, artist.getArtist()); |
455 | + sqlStmt.bindString(i++, albumList); |
456 | + sqlStmt.bindLong(i++, albumListSize); |
457 | + sqlStmt.bindLong(i++, artist.getSongCount()); |
458 | + |
459 | + sqlStmt.bindString(i++, artist.getArtistUrl()); |
460 | + sqlStmt.bindString(i++, artist.getArtistArtUrl()); |
461 | + |
462 | + sqlStmt.bindString(i++, artist.getId()); |
463 | + // Can't use executeUpdateDelete on API < 11 |
464 | + sqlStmt.execute(); |
465 | + long rowsUpdated = getChanges(db); |
466 | + |
467 | + if (rowsUpdated == 0L) { |
468 | + sqlStmt = db.compileStatement(getInsertSql()); |
469 | + i = 1; |
470 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
471 | + sqlStmt.bindString(i++, artist.getId()); |
472 | + |
473 | + sqlStmt.bindString(i++, artist.getArtist()); |
474 | + sqlStmt.bindString(i++, albumList); |
475 | + sqlStmt.bindLong(i++, albumListSize); |
476 | + sqlStmt.bindLong(i++, artist.getSongCount()); |
477 | + |
478 | + sqlStmt.bindString(i++, artist.getArtistUrl()); |
479 | + sqlStmt.bindString(i++, artist.getArtistArtUrl()); |
480 | + |
481 | + long rowId = sqlStmt.executeInsert(); |
482 | + isSuccess = rowId != -1; |
483 | + } else { |
484 | + isSuccess = rowsUpdated == 1; |
485 | + } |
486 | + |
487 | + // Insert artist albums. |
488 | + sqlStmt = db.compileStatement(getSecondaryInsertSql()); |
489 | + final String artistId = artist.getId(); |
490 | + final ArrayList<String> albumIds = artist.getAlbumIds(); |
491 | + for (String albumId : albumIds) { |
492 | + sqlStmt.clearBindings(); |
493 | + sqlStmt.bindLong(1, System.currentTimeMillis()); |
494 | + sqlStmt.bindString(2, artistId); |
495 | + sqlStmt.bindString(3, albumId); |
496 | + long rowId = sqlStmt.executeInsert(); |
497 | + isSuccess = isSuccess && (rowId != -1); |
498 | + } |
499 | + |
500 | + return isSuccess; |
501 | + } |
502 | + |
503 | + @Override |
504 | + public String onGetInsertSql() { |
505 | + return "INSERT INTO " + Tables.ARTISTS + "(" + |
506 | + Artists.UPDATED + ", " + |
507 | + Artists.ARTIST_ID + ", " + |
508 | + |
509 | + Artists.ARTIST_NAME + ", " + |
510 | + Artists.ALBUM_LIST + ", " + |
511 | + Artists.ALBUM_COUNT + ", " + |
512 | + Artists.SONG_COUNT + ", " + |
513 | + |
514 | + Artists.ARTIST_URL + ", " + |
515 | + Artists.ARTIST_ART_URL + |
516 | + |
517 | + ") VALUES (?, ?, " + |
518 | + "?, ?, ?, ?, " + |
519 | + "?, ?" + |
520 | + ")"; |
521 | + } |
522 | + |
523 | + @Override |
524 | + public String onGetSecondaryInsertSql() { |
525 | + return "INSERT INTO " + Tables.ARTISTS_ALBUMS + "(" + |
526 | + |
527 | + ArtistAlbums.UPDATED + ", " + |
528 | + ArtistAlbums.ARTIST_ID + ", " + |
529 | + ArtistAlbums.ALBUM_ID + |
530 | + |
531 | + ") VALUES (?, ?, ?)"; |
532 | + } |
533 | + |
534 | + @Override |
535 | + public String onGetUpdateSql() { |
536 | + return "UPDATE " + Tables.ARTISTS + " SET " + |
537 | + Artists.UPDATED + "=?, " + |
538 | + |
539 | + Artists.ARTIST_NAME + "=?, " + |
540 | + Artists.ALBUM_LIST + "=?, " + |
541 | + Artists.ALBUM_COUNT + "=?, " + |
542 | + Artists.SONG_COUNT + "=?, " + |
543 | + |
544 | + Artists.ARTIST_URL + "=?, " + |
545 | + Artists.ARTIST_ART_URL + "=? " + |
546 | + |
547 | + "WHERE " + Artists.ARTIST_ID + "=?"; |
548 | + } |
549 | +} |
550 | |
551 | === added file 'src/com/ubuntuone/android/music/provider/dao/Dao.java' |
552 | --- src/com/ubuntuone/android/music/provider/dao/Dao.java 1970-01-01 00:00:00 +0000 |
553 | +++ src/com/ubuntuone/android/music/provider/dao/Dao.java 2012-11-21 17:34:22 +0000 |
554 | @@ -0,0 +1,76 @@ |
555 | +package com.ubuntuone.android.music.provider.dao; |
556 | + |
557 | +import android.database.sqlite.SQLiteDatabase; |
558 | +import android.database.sqlite.SQLiteStatement; |
559 | + |
560 | +public abstract class Dao |
561 | +{ |
562 | + private String mInsertSql; |
563 | + private String mSecondaryInsertSql; |
564 | + private String mUdpateSql; |
565 | + |
566 | + /** |
567 | + * Performs a lazy initialization with {@code Dao#onGetInsertSql()}. |
568 | + * |
569 | + * @return The cached SQL INSERT string. |
570 | + */ |
571 | + public String getInsertSql() { |
572 | + if (mInsertSql == null) { |
573 | + mInsertSql = onGetInsertSql(); |
574 | + } |
575 | + return mInsertSql; |
576 | + } |
577 | + |
578 | + /** |
579 | + * Performs a lazy initialization with {@code Dao#onGetSecondaryInsertSql()}. |
580 | + * |
581 | + * @return The cached secondary SQL INSERT string. |
582 | + */ |
583 | + public String getSecondaryInsertSql() { |
584 | + if (mSecondaryInsertSql == null) { |
585 | + mSecondaryInsertSql = onGetSecondaryInsertSql(); |
586 | + } |
587 | + return mSecondaryInsertSql; |
588 | + } |
589 | + |
590 | + /** |
591 | + * Performs a lazy initialization with {@code Dao#onGetUpdateSql()}. |
592 | + * |
593 | + * @return The cached SQL UPDATE string. |
594 | + */ |
595 | + public String getUpdateSql() { |
596 | + if (mUdpateSql == null) { |
597 | + mUdpateSql = onGetUpdateSql(); |
598 | + } |
599 | + return mUdpateSql; |
600 | + } |
601 | + |
602 | + public long getChanges(SQLiteDatabase db) { |
603 | + SQLiteStatement countStmt = db.compileStatement("SELECT changes()"); |
604 | + return countStmt.simpleQueryForLong(); |
605 | + } |
606 | + |
607 | + /** |
608 | + * Override to return the SQL INSERT string. |
609 | + * |
610 | + * @return The SQL INSERT string. |
611 | + */ |
612 | + public abstract String onGetInsertSql(); |
613 | + |
614 | + |
615 | + /** |
616 | + * Override to return the secondary SQL INSERT string. |
617 | + * |
618 | + * @return The secondary SQL INSERT string. |
619 | + */ |
620 | + public String onGetSecondaryInsertSql() { |
621 | + return null; |
622 | + } |
623 | + |
624 | + /** |
625 | + * Override to return the SQL UPDATE string. |
626 | + * |
627 | + * @return The SQL UPDATE string. |
628 | + */ |
629 | + public abstract String onGetUpdateSql(); |
630 | +} |
631 | |
632 | === added file 'src/com/ubuntuone/android/music/provider/dao/GenreDao.java' |
633 | --- src/com/ubuntuone/android/music/provider/dao/GenreDao.java 1970-01-01 00:00:00 +0000 |
634 | +++ src/com/ubuntuone/android/music/provider/dao/GenreDao.java 2012-11-21 17:34:22 +0000 |
635 | @@ -0,0 +1,86 @@ |
636 | +package com.ubuntuone.android.music.provider.dao; |
637 | + |
638 | +import android.content.ContentResolver; |
639 | +import android.content.ContentValues; |
640 | +import android.database.sqlite.SQLiteDatabase; |
641 | +import android.database.sqlite.SQLiteStatement; |
642 | +import android.text.TextUtils; |
643 | + |
644 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
645 | +import com.ubuntuone.android.music.provider.MusicContract.Genres; |
646 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
647 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
648 | +import com.ubuntuone.android.music.provider.MusicProvider; |
649 | +import com.ubuntuone.android.music.util.HashUtils; |
650 | +import com.ubuntuone.api.music.model.U1Song; |
651 | + |
652 | +public class GenreDao extends Dao |
653 | +{ |
654 | + public GenreDao() { |
655 | + } |
656 | + |
657 | + /** |
658 | + * Inserts song genre. Backed by {@link MusicProvider}. |
659 | + * |
660 | + * @param resolver |
661 | + * The content resolver. |
662 | + * @param song |
663 | + * The {@link U1Song} of which genre to save. |
664 | + */ |
665 | + public void updateOrInsert(ContentResolver resolver, U1Song song) { |
666 | + String genre = song.getGenre(); |
667 | + String lcGenre = genre != null ? genre.trim().toLowerCase() : null; |
668 | + if (!TextUtils.isEmpty(lcGenre) && |
669 | + !lcGenre.equals("null") && !lcGenre.equals("genre")) { |
670 | + // XXX Do we want all genres uppercase? If so, toUpperCase() genre below. |
671 | + ContentValues genreValues = MusicContentValues.forGenre(genre.trim()); |
672 | + resolver.insert(Genres.CONTENT_URI, genreValues); |
673 | + } |
674 | + } |
675 | + |
676 | + /** |
677 | + * Inserts song genre. Backed by {@link MusicDatabase}. |
678 | + * |
679 | + * @param db |
680 | + * The {@link MusicDatabase} instance. |
681 | + * @param song |
682 | + * The {@link U1Song} of which genre to save. |
683 | + * @return Always true for genre. |
684 | + */ |
685 | + public boolean updateOrInsert(SQLiteDatabase db, String genre) { |
686 | + final SQLiteStatement genreInsert = db.compileStatement(getInsertSql()); |
687 | + genreInsert.clearBindings(); |
688 | + |
689 | + String lcGenre = genre != null ? genre.trim().toLowerCase() : null; |
690 | + if (TextUtils.isEmpty(lcGenre) || |
691 | + lcGenre.equals("null") || lcGenre.equals("genre")) { |
692 | + // Ignore generic crap. Assume genre was inserted, we don't care. |
693 | + return true; |
694 | + } |
695 | + String genreId = HashUtils.md5(genre.toUpperCase()); |
696 | + |
697 | + int j = 1; // Index to the parameter to bind. |
698 | + genreInsert.bindLong(j++, System.currentTimeMillis()); |
699 | + genreInsert.bindString(j++, genreId); |
700 | + genreInsert.bindString(j++, genre); |
701 | + |
702 | + genreInsert.executeInsert(); |
703 | + // Assume genre was inserted, we don't care. |
704 | + return true; |
705 | + } |
706 | + |
707 | + @Override |
708 | + public String onGetInsertSql() { |
709 | + return "INSERT INTO " + Tables.GENRES + "(" + |
710 | + Genres.UPDATED + ", " + |
711 | + Genres.GENRE_ID + ", " + |
712 | + Genres.GENRE_TITLE + |
713 | + ") VALUES (?, ?, ?)"; |
714 | + } |
715 | + |
716 | + @Override |
717 | + public String onGetUpdateSql() { |
718 | + // Not used for genre. |
719 | + return null; |
720 | + } |
721 | +} |
722 | |
723 | === added file 'src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java' |
724 | --- src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java 1970-01-01 00:00:00 +0000 |
725 | +++ src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java 2012-11-21 17:34:22 +0000 |
726 | @@ -0,0 +1,109 @@ |
727 | +package com.ubuntuone.android.music.provider.dao; |
728 | + |
729 | +import android.content.ContentResolver; |
730 | +import android.content.ContentValues; |
731 | +import android.database.sqlite.SQLiteDatabase; |
732 | +import android.database.sqlite.SQLiteStatement; |
733 | +import android.net.Uri; |
734 | + |
735 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
736 | +import com.ubuntuone.android.music.provider.MusicContract.Playlists; |
737 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
738 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
739 | +import com.ubuntuone.android.music.provider.MusicProvider; |
740 | +import com.ubuntuone.api.music.model.U1Playlist; |
741 | + |
742 | +public class PlaylistDao extends Dao |
743 | +{ |
744 | + public PlaylistDao() { |
745 | + } |
746 | + |
747 | + /** |
748 | + * Updates the playlist. If the playlist doesn't exist, inserts the playlist. |
749 | + * Backed by {@link MusicProvider}. |
750 | + * |
751 | + * @param resolver |
752 | + * The content resolver. |
753 | + * @param playlist |
754 | + * The {@link U1Playlist} to save. |
755 | + */ |
756 | + public void updateOrInsert(ContentResolver resolver, U1Playlist playlist) { |
757 | + ContentValues values = MusicContentValues.forPlaylist(playlist); |
758 | + Uri playlistUri = Playlists.buildPlaylistUri(playlist.getId()); |
759 | + int count = resolver.update(playlistUri, values, null, null); |
760 | + if (count == 0) { |
761 | + resolver.insert(Playlists.CONTENT_URI, values); |
762 | + } |
763 | + } |
764 | + |
765 | + /** |
766 | + * Updates the playlist. If the playlist doesn't exist, inserts the playlist. |
767 | + * Backed by {@link MusicDatabase}. |
768 | + * |
769 | + * @param db |
770 | + * The {@link MusicDatabase} instance. |
771 | + * @param playlist |
772 | + * The {@link U1Playlist} to save. |
773 | + * @return True if update or insert succeeded, false otherwise. |
774 | + */ |
775 | + public boolean updateOrInsert(SQLiteDatabase db, U1Playlist playlist) { |
776 | + boolean isSuccess = false; |
777 | + |
778 | + SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql()); |
779 | + int i = 1; // Index to the parameter to bind. |
780 | + |
781 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
782 | + |
783 | + sqlStmt.bindString(i++, playlist.getName()); |
784 | + sqlStmt.bindLong(i++, playlist.getSongCount()); |
785 | + sqlStmt.bindString(i++, playlist.getPlaylistUrl()); |
786 | + |
787 | + sqlStmt.bindString(i++, playlist.getId()); |
788 | + // Can't use executeUpdateDelete on API < 11 |
789 | + sqlStmt.execute(); |
790 | + long rowsUpdated = getChanges(db); |
791 | + |
792 | + if (rowsUpdated == 0L) { |
793 | + sqlStmt = db.compileStatement(getInsertSql()); |
794 | + i = 1; |
795 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
796 | + |
797 | + sqlStmt.bindString(i++, playlist.getId()); |
798 | + sqlStmt.bindString(i++, playlist.getName()); |
799 | + sqlStmt.bindLong(i++, playlist.getSongCount()); |
800 | + sqlStmt.bindString(i++, playlist.getPlaylistUrl()); |
801 | + |
802 | + long rowId = sqlStmt.executeInsert(); |
803 | + isSuccess = rowId != -1; |
804 | + } else { |
805 | + isSuccess = rowsUpdated == 1; |
806 | + } |
807 | + return isSuccess; |
808 | + } |
809 | + |
810 | + @Override |
811 | + public String onGetInsertSql() { |
812 | + return "INSERT INTO " + Tables.PLAYLISTS + "(" + |
813 | + Playlists.UPDATED + ", " + |
814 | + Playlists.PLAYLIST_ID + ", " + |
815 | + |
816 | + Playlists.PLAYLIST_NAME + ", " + |
817 | + Playlists.PLAYLIST_SONG_COUNT + ", " + |
818 | + Playlists.PLAYLIST_URL + |
819 | + |
820 | + ") VALUES (?, ?, " + |
821 | + "?, ?, ?" + |
822 | + ")"; |
823 | + } |
824 | + |
825 | + @Override |
826 | + public String onGetUpdateSql() { |
827 | + return "UPDATE " + Tables.PLAYLISTS + " SET " + |
828 | + Playlists.UPDATED + "=?, " + |
829 | + Playlists.PLAYLIST_NAME + "=?, " + |
830 | + Playlists.PLAYLIST_SONG_COUNT + "=?, " + |
831 | + Playlists.PLAYLIST_URL + "=? " + |
832 | + "WHERE " + Playlists.PLAYLIST_ID + "=?"; |
833 | + |
834 | + } |
835 | +} |
836 | |
837 | === added file 'src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java' |
838 | --- src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java 1970-01-01 00:00:00 +0000 |
839 | +++ src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java 2012-11-21 17:34:22 +0000 |
840 | @@ -0,0 +1,97 @@ |
841 | +package com.ubuntuone.android.music.provider.dao; |
842 | + |
843 | +import android.content.ContentResolver; |
844 | +import android.content.ContentValues; |
845 | +import android.database.sqlite.SQLiteDatabase; |
846 | +import android.database.sqlite.SQLiteStatement; |
847 | +import android.net.Uri; |
848 | + |
849 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
850 | +import com.ubuntuone.android.music.provider.MusicContract.PlaylistSongs; |
851 | +import com.ubuntuone.android.music.provider.MusicContract.Playlists; |
852 | +import com.ubuntuone.android.music.provider.MusicContract.Songs; |
853 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
854 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
855 | +import com.ubuntuone.android.music.provider.MusicProvider; |
856 | +import com.ubuntuone.api.music.model.U1Song; |
857 | + |
858 | +public class PlaylistSongDao extends Dao |
859 | +{ |
860 | + public PlaylistSongDao() { |
861 | + } |
862 | + |
863 | + /** |
864 | + * Updates the playlist song. If the playlist song doesn't exist, inserts |
865 | + * the playlist song. Backed by {@link MusicProvider}. |
866 | + * |
867 | + * @param resolver |
868 | + * The content resolver. |
869 | + * @param playlistId |
870 | + * The playlist id of the playlist to save the song to. |
871 | + * @param song |
872 | + * The {@link U1Song} to save. |
873 | + */ |
874 | + public void updateOrInsert(ContentResolver resolver, String playlistId, U1Song song) { |
875 | + ContentValues values = MusicContentValues.forPlaylistSong(playlistId, song.getId()); |
876 | + Uri playlistSongsUri = Playlists.buildPlaylistSongUri(playlistId, song.getId()); |
877 | + int count = resolver.update(playlistSongsUri, values, null, null); |
878 | + if (count == 0) { |
879 | + resolver.insert(playlistSongsUri, values); |
880 | + } |
881 | + } |
882 | + |
883 | + /** |
884 | + * Updates the playlist song. If the playlist song doesn't exist, inserts |
885 | + * the playlist song. Backed by {@link MusicDatabase}. |
886 | + * |
887 | + * @param db |
888 | + * The {@link MusicDatabase} instance. |
889 | + * @param playlistId |
890 | + * The playlist id of the playlist to save the song to. |
891 | + * @param song |
892 | + * The {@link U1Song} to save. |
893 | + * @return True if update or insert succeeded, false otherwise. |
894 | + */ |
895 | + public boolean updateOrInsert(SQLiteDatabase db, String playlistId, String songId) { |
896 | + boolean isSuccess = false; |
897 | + |
898 | + SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql()); |
899 | + int i = 1; // Index to the parameter to bind. |
900 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
901 | + sqlStmt.bindString(i++, playlistId); |
902 | + sqlStmt.bindString(i++, songId); |
903 | + // Can't use executeUpdateDelete on API < 11 |
904 | + sqlStmt.execute(); |
905 | + long rowsUpdated = getChanges(db); |
906 | + |
907 | + if (rowsUpdated == 0L) { |
908 | + sqlStmt = db.compileStatement(getInsertSql()); |
909 | + i = 1; |
910 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
911 | + sqlStmt.bindString(i++, playlistId); |
912 | + sqlStmt.bindString(i++, songId); |
913 | + |
914 | + long rowId = sqlStmt.executeInsert(); |
915 | + isSuccess = rowId != -1; |
916 | + } else { |
917 | + isSuccess = rowsUpdated == 1; |
918 | + } |
919 | + return isSuccess; |
920 | + } |
921 | + |
922 | + @Override |
923 | + public String onGetInsertSql() { |
924 | + return "INSERT INTO " + Tables.PLAYLISTS_SONGS + "(" + |
925 | + PlaylistSongs.UPDATED + ", " + |
926 | + PlaylistSongs.PLAYLIST_ID + ", " + |
927 | + PlaylistSongs.SONG_ID + |
928 | + ") VALUES (?, ?, ?)"; |
929 | + } |
930 | + |
931 | + @Override |
932 | + public String onGetUpdateSql() { |
933 | + return "UPDATE " + Tables.PLAYLISTS_SONGS + " SET " + |
934 | + PlaylistSongs.UPDATED + "=? " + |
935 | + "WHERE " + PlaylistSongs.PLAYLIST_ID + "=? AND " + Songs.SONG_ID + "=?"; |
936 | + } |
937 | +} |
938 | |
939 | === added file 'src/com/ubuntuone/android/music/provider/dao/SongDao.java' |
940 | --- src/com/ubuntuone/android/music/provider/dao/SongDao.java 1970-01-01 00:00:00 +0000 |
941 | +++ src/com/ubuntuone/android/music/provider/dao/SongDao.java 2012-11-21 17:34:22 +0000 |
942 | @@ -0,0 +1,194 @@ |
943 | +package com.ubuntuone.android.music.provider.dao; |
944 | + |
945 | +import static com.ubuntuone.android.music.provider.MusicContentValues.getGenreId; |
946 | +import android.content.ContentResolver; |
947 | +import android.content.ContentValues; |
948 | +import android.database.sqlite.SQLiteDatabase; |
949 | +import android.database.sqlite.SQLiteStatement; |
950 | +import android.net.Uri; |
951 | + |
952 | +import com.ubuntuone.android.music.provider.MusicContentValues; |
953 | +import com.ubuntuone.android.music.provider.MusicContract.Songs; |
954 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
955 | +import com.ubuntuone.android.music.provider.MusicDatabase.Tables; |
956 | +import com.ubuntuone.android.music.provider.MusicProvider; |
957 | +import com.ubuntuone.api.music.model.U1Song; |
958 | + |
959 | +public class SongDao extends Dao |
960 | +{ |
961 | + public SongDao() { |
962 | + } |
963 | + |
964 | + /** |
965 | + * Updates the song. If the song doesn't exist, inserts the song. Backed by |
966 | + * {@link MusicProvider}. |
967 | + * |
968 | + * @param resolver |
969 | + * The content resolver. |
970 | + * @param song |
971 | + * The {@link U1Song} to save. |
972 | + */ |
973 | + public void updateOrInsert(ContentResolver resolver, U1Song song) { |
974 | + ContentValues values = MusicContentValues.forSong(song); |
975 | + Uri songUri = Songs.buildSongUri(song.getId()); |
976 | + int rowsUpdated = resolver.update(songUri, values, null, null); |
977 | + if (rowsUpdated == 0) { |
978 | + resolver.insert(Songs.CONTENT_URI, values); |
979 | + } |
980 | + } |
981 | + |
982 | + /** |
983 | + * Updates the song. If the song doesn't exist, inserts the song. Backed by |
984 | + * {@link MusicDatabase}. |
985 | + * |
986 | + * @param db |
987 | + * The {@link MusicDatabase} instance. |
988 | + * @param song |
989 | + * The {@link U1Song} to save. |
990 | + * @return True if update or insert succeeded, false otherwise. |
991 | + */ |
992 | + public boolean updateOrInsert(SQLiteDatabase db, U1Song song) { |
993 | + boolean isSuccess = false; |
994 | + |
995 | + SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql()); |
996 | + int i = 1; // Index to the parameter to bind. |
997 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
998 | + |
999 | + sqlStmt.bindString(i++, song.getTitle()); |
1000 | + sqlStmt.bindString(i++, song.getAlbum()); |
1001 | + sqlStmt.bindString(i++, song.getAlbumId()); |
1002 | + sqlStmt.bindString(i++, song.getAlbumArtist()); |
1003 | + |
1004 | + sqlStmt.bindString(i++, song.getArtist()); |
1005 | + sqlStmt.bindString(i++, song.getArtistId()); |
1006 | + sqlStmt.bindString(i++, song.getGenre()); |
1007 | + sqlStmt.bindString(i++, getGenreId(song.getGenre())); |
1008 | + |
1009 | + sqlStmt.bindLong(i++, song.getYear()); |
1010 | + sqlStmt.bindLong(i++, song.getDiscNumber()); |
1011 | + sqlStmt.bindLong(i++, song.getTrack()); |
1012 | + sqlStmt.bindLong(i++, song.getDuration()); |
1013 | + |
1014 | + sqlStmt.bindLong(i++, song.getSize()); |
1015 | + sqlStmt.bindLong(i++, song.getBitRate()); |
1016 | + sqlStmt.bindString(i++, song.getSuffix()); |
1017 | + sqlStmt.bindString(i++, song.getContentType()); |
1018 | + |
1019 | + sqlStmt.bindString(i++, song.getSongUrl()); |
1020 | + sqlStmt.bindString(i++, song.getSongArtUrl()); |
1021 | + sqlStmt.bindString(i++, song.getSongStreamUrl()); |
1022 | + |
1023 | + sqlStmt.bindString(i++, song.getId()); |
1024 | + // Can't use executeUpdateDelete on API < 11 |
1025 | + sqlStmt.execute(); |
1026 | + long rowsUpdated = getChanges(db); |
1027 | + |
1028 | + if (rowsUpdated == 0L) { |
1029 | + sqlStmt = db.compileStatement(getInsertSql()); |
1030 | + i = 1; |
1031 | + sqlStmt.bindLong(i++, System.currentTimeMillis()); |
1032 | + sqlStmt.bindString(i++, song.getId()); |
1033 | + |
1034 | + sqlStmt.bindString(i++, song.getTitle()); |
1035 | + sqlStmt.bindString(i++, song.getAlbum()); |
1036 | + sqlStmt.bindString(i++, song.getAlbumId()); |
1037 | + sqlStmt.bindString(i++, song.getAlbumArtist()); |
1038 | + |
1039 | + sqlStmt.bindString(i++, song.getArtist()); |
1040 | + sqlStmt.bindString(i++, song.getArtistId()); |
1041 | + sqlStmt.bindString(i++, song.getGenre()); |
1042 | + sqlStmt.bindString(i++, getGenreId(song.getGenre())); |
1043 | + |
1044 | + sqlStmt.bindLong(i++, song.getYear()); |
1045 | + sqlStmt.bindLong(i++, song.getDiscNumber()); |
1046 | + sqlStmt.bindLong(i++, song.getTrack()); |
1047 | + sqlStmt.bindLong(i++, song.getDuration()); |
1048 | + |
1049 | + sqlStmt.bindLong(i++, song.getSize()); |
1050 | + sqlStmt.bindLong(i++, song.getBitRate()); |
1051 | + sqlStmt.bindString(i++, song.getSuffix()); |
1052 | + sqlStmt.bindString(i++, song.getContentType()); |
1053 | + |
1054 | + sqlStmt.bindString(i++, song.getSongUrl()); |
1055 | + sqlStmt.bindString(i++, song.getSongArtUrl()); |
1056 | + sqlStmt.bindString(i++, song.getSongStreamUrl()); |
1057 | + |
1058 | + long rowId = sqlStmt.executeInsert(); |
1059 | + isSuccess = rowId != -1; |
1060 | + } else { |
1061 | + isSuccess = rowsUpdated == 1; |
1062 | + } |
1063 | + return isSuccess; |
1064 | + } |
1065 | + |
1066 | + @Override |
1067 | + public String onGetInsertSql() { |
1068 | + return "INSERT INTO " + Tables.SONGS + "(" + |
1069 | + Songs.UPDATED + ", " + |
1070 | + Songs.SONG_ID + ", " + |
1071 | + |
1072 | + Songs.SONG_TITLE + ", " + |
1073 | + Songs.SONG_ALBUM + ", " + |
1074 | + Songs.SONG_ALBUM_ID + ", " + |
1075 | + Songs.SONG_ALBUM_ARTIST + ", " + |
1076 | + |
1077 | + Songs.SONG_ARTIST + ", " + |
1078 | + Songs.SONG_ARTIST_ID + ", " + |
1079 | + Songs.SONG_GENRE + ", " + |
1080 | + Songs.SONG_GENRE_ID + ", " + |
1081 | + |
1082 | + Songs.SONG_YEAR + ", " + |
1083 | + Songs.SONG_DISC_NUMBER + ", " + |
1084 | + Songs.SONG_TRACK + ", " + |
1085 | + Songs.SONG_DURATION + ", " + |
1086 | + |
1087 | + Songs.SONG_SIZE + ", " + |
1088 | + Songs.SONG_BIT_RATE + ", " + |
1089 | + Songs.SONG_SUFFIX + ", " + |
1090 | + Songs.SONG_CONTENT_TYPE + ", " + |
1091 | + |
1092 | + Songs.SONG_URL + ", " + |
1093 | + Songs.SONG_ART_URL + ", " + |
1094 | + Songs.SONG_STREAM_URL + |
1095 | + |
1096 | + ") VALUES (?, ?, " + |
1097 | + "?, ?, ?, ?, " + |
1098 | + "?, ?, ?, ?, " + |
1099 | + "?, ?, ?, ?, " + |
1100 | + "?, ?, ?, ?, " + |
1101 | + "?, ?, ?" + |
1102 | + ")"; |
1103 | + } |
1104 | + |
1105 | + @Override |
1106 | + public String onGetUpdateSql() { |
1107 | + return "UPDATE " + Tables.SONGS + " SET " + |
1108 | + Songs.UPDATED + "=?, " + |
1109 | + |
1110 | + Songs.SONG_TITLE + "=?, " + |
1111 | + Songs.SONG_ALBUM + "=?, " + |
1112 | + Songs.SONG_ALBUM_ID + "=?, " + |
1113 | + Songs.SONG_ALBUM_ARTIST + "=?, " + |
1114 | + |
1115 | + Songs.SONG_ARTIST + "=?, " + |
1116 | + Songs.SONG_ARTIST_ID + "=?, " + |
1117 | + Songs.SONG_GENRE + "=?, " + |
1118 | + Songs.SONG_GENRE_ID + "=?, " + |
1119 | + |
1120 | + Songs.SONG_YEAR + "=?, " + |
1121 | + Songs.SONG_DISC_NUMBER + "=?, " + |
1122 | + Songs.SONG_TRACK + "=?, " + |
1123 | + Songs.SONG_DURATION + "=?, " + |
1124 | + |
1125 | + Songs.SONG_SIZE + "=?, " + |
1126 | + Songs.SONG_BIT_RATE + "=?, " + |
1127 | + Songs.SONG_SUFFIX + "=?, " + |
1128 | + Songs.SONG_CONTENT_TYPE + "=?, " + |
1129 | + |
1130 | + Songs.SONG_URL + "=?, " + |
1131 | + Songs.SONG_ART_URL + "=?, " + |
1132 | + Songs.SONG_STREAM_URL + "=? " + |
1133 | + |
1134 | + "WHERE " + Songs.SONG_ID + "=?"; |
1135 | + } |
1136 | +} |
1137 | |
1138 | === modified file 'src/com/ubuntuone/android/music/service/MusicService.java' |
1139 | --- src/com/ubuntuone/android/music/service/MusicService.java 2012-11-08 23:02:13 +0000 |
1140 | +++ src/com/ubuntuone/android/music/service/MusicService.java 2012-11-21 17:34:22 +0000 |
1141 | @@ -384,7 +384,7 @@ |
1142 | |
1143 | public synchronized void resume() { |
1144 | try { |
1145 | - if (UbuntuOneMusic.DEBUG_SHOULD_PLAY) { |
1146 | + if (UbuntuOneMusic.SHOULD_PLAY) { |
1147 | mMediaPlayer.start(); |
1148 | } |
1149 | setPlayerState(STARTED); |
1150 | @@ -594,7 +594,7 @@ |
1151 | mMediaPlayer.seekTo(position); |
1152 | } |
1153 | |
1154 | - if (UbuntuOneMusic.DEBUG_SHOULD_PLAY) { |
1155 | + if (UbuntuOneMusic.SHOULD_PLAY) { |
1156 | mMediaPlayer.start(); |
1157 | } |
1158 | setPlayerState(STARTED); |
1159 | |
1160 | === modified file 'src/com/ubuntuone/android/music/service/SyncService.java' |
1161 | --- src/com/ubuntuone/android/music/service/SyncService.java 2012-11-08 14:14:54 +0000 |
1162 | +++ src/com/ubuntuone/android/music/service/SyncService.java 2012-11-21 17:34:22 +0000 |
1163 | @@ -21,32 +21,32 @@ |
1164 | |
1165 | package com.ubuntuone.android.music.service; |
1166 | |
1167 | -import static com.ubuntuone.android.music.util.LogUtils.LOGD; |
1168 | -import static com.ubuntuone.android.music.util.LogUtils.LOGE; |
1169 | import static com.ubuntuone.android.music.util.LogUtils.makeLogTag; |
1170 | - |
1171 | -import java.util.ArrayList; |
1172 | - |
1173 | import android.app.IntentService; |
1174 | import android.content.ContentResolver; |
1175 | -import android.content.ContentValues; |
1176 | import android.content.Context; |
1177 | import android.content.Intent; |
1178 | import android.database.Cursor; |
1179 | -import android.net.Uri; |
1180 | +import android.database.sqlite.SQLiteDatabase; |
1181 | import android.os.Bundle; |
1182 | import android.os.ResultReceiver; |
1183 | import android.util.Log; |
1184 | |
1185 | import com.ubuntuone.android.music.R; |
1186 | import com.ubuntuone.android.music.UbuntuOneMusic; |
1187 | -import com.ubuntuone.android.music.provider.MusicContentValues; |
1188 | import com.ubuntuone.android.music.provider.MusicContract.Albums; |
1189 | import com.ubuntuone.android.music.provider.MusicContract.Artists; |
1190 | import com.ubuntuone.android.music.provider.MusicContract.Playlists; |
1191 | import com.ubuntuone.android.music.provider.MusicContract.Songs; |
1192 | import com.ubuntuone.android.music.provider.MusicContract.SyncColumns; |
1193 | +import com.ubuntuone.android.music.provider.MusicDatabase; |
1194 | import com.ubuntuone.android.music.provider.MusicProviderUtils; |
1195 | +import com.ubuntuone.android.music.provider.dao.AlbumDao; |
1196 | +import com.ubuntuone.android.music.provider.dao.ArtistDao; |
1197 | +import com.ubuntuone.android.music.provider.dao.GenreDao; |
1198 | +import com.ubuntuone.android.music.provider.dao.PlaylistDao; |
1199 | +import com.ubuntuone.android.music.provider.dao.PlaylistSongDao; |
1200 | +import com.ubuntuone.android.music.provider.dao.SongDao; |
1201 | import com.ubuntuone.android.music.util.AccountUtils; |
1202 | import com.ubuntuone.android.music.util.UIUtils; |
1203 | import com.ubuntuone.api.music.U1MusicAPI; |
1204 | @@ -73,7 +73,8 @@ |
1205 | public static final int SYNC_STARTED = 1; |
1206 | public static final int SYNC_PROGRESS = 2; |
1207 | public static final int SYNC_FINISHED = 3; |
1208 | - |
1209 | + |
1210 | + private static final boolean DIRECT_SQL = true; |
1211 | |
1212 | private static int sSyncStatus = 0; |
1213 | |
1214 | @@ -104,7 +105,7 @@ |
1215 | mReceiver = intent.getParcelableExtra(EXTRA_RECEIVER); |
1216 | if (action != null && ACTION_SYNC_MUSIC_METADATA.equals(action)) { |
1217 | mTimeSyncStarted = System.currentTimeMillis(); |
1218 | - if (mApi != null && UbuntuOneMusic.DEBUG_SHOULD_SYNC) { |
1219 | + if (mApi != null && UbuntuOneMusic.SHOULD_SYNC) { |
1220 | sSyncStatus = SYNC_STARTED; |
1221 | if (mReceiver != null) mReceiver.send(SYNC_STARTED, Bundle.EMPTY); |
1222 | syncMusicMetadata(); |
1223 | @@ -122,37 +123,49 @@ |
1224 | syncSongs(); |
1225 | syncPlaylists(); |
1226 | syncPlaylistSongs(); |
1227 | - // Don't purge if network has gone away. |
1228 | + // Purge only if network connection still present. |
1229 | if (UIUtils.isNetworkConnected(this)) { |
1230 | purgeInvalidData(mTimeSyncStarted); |
1231 | } |
1232 | } |
1233 | |
1234 | private void syncArtists() { |
1235 | + final long timeMillis = System.currentTimeMillis(); |
1236 | mApi.getArtists(mArtistListener); |
1237 | + final long nowMillis = System.currentTimeMillis(); |
1238 | + Log.i(TAG, "Artists sync took " + (nowMillis - timeMillis) + "ms"); |
1239 | } |
1240 | |
1241 | private void syncAlbums() { |
1242 | + final long timeMillis = System.currentTimeMillis(); |
1243 | mApi.getAlbums(mAlbumListener); |
1244 | + final long nowMillis = System.currentTimeMillis(); |
1245 | + Log.i(TAG, "Albums sync took " + (nowMillis - timeMillis) + "ms"); |
1246 | } |
1247 | |
1248 | private void syncSongs() { |
1249 | + final long timeMillis = System.currentTimeMillis(); |
1250 | mApi.getSongs(mSongListener); |
1251 | + final long nowMillis = System.currentTimeMillis(); |
1252 | + Log.i(TAG, "Songs sync took " + (nowMillis - timeMillis) + "ms"); |
1253 | } |
1254 | |
1255 | private void syncPlaylists() { |
1256 | + final long timeMillis = System.currentTimeMillis(); |
1257 | mApi.getPlaylists(mPlaylistListener); |
1258 | + final long nowMillis = System.currentTimeMillis(); |
1259 | + Log.i(TAG, "Playlists sync took " + (nowMillis - timeMillis) + "ms"); |
1260 | } |
1261 | |
1262 | private void syncPlaylistSongs() { |
1263 | + final long timeMillis = System.currentTimeMillis(); |
1264 | Cursor cursor = null; |
1265 | try { |
1266 | String[] projection = new String[] { Playlists.PLAYLIST_ID }; |
1267 | cursor = getContentResolver().query(Playlists.CONTENT_URI, projection, |
1268 | null, null, null); |
1269 | while (cursor.moveToNext()) { |
1270 | - String playlistId = cursor.getString( |
1271 | - cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID)); |
1272 | + String playlistId = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_ID)); |
1273 | if (MusicProviderUtils.QUEUE_ID.equals(playlistId)) continue; |
1274 | mPlaylistSongListener.setPlaylist(playlistId); |
1275 | mApi.getPlaylist(playlistId, mPlaylistSongListener); |
1276 | @@ -160,163 +173,197 @@ |
1277 | } finally { |
1278 | if (cursor != null) cursor.close(); |
1279 | } |
1280 | + final long nowMillis = System.currentTimeMillis(); |
1281 | + Log.i(TAG, "Playlist songs sync took " + (nowMillis - timeMillis) + "ms"); |
1282 | } |
1283 | |
1284 | private U1ArtistListener mArtistListener = new U1ArtistListener() { |
1285 | + private SQLiteDatabase db; |
1286 | + private ArtistDao artistDao = new ArtistDao(); |
1287 | + private Bundle progressBundle = new Bundle(); |
1288 | + private Failure failure = null; |
1289 | private int artistCount = 0; |
1290 | - private int artistAlbumCount = 0; |
1291 | - |
1292 | - private Bundle progressBundle = new Bundle(); |
1293 | |
1294 | @Override |
1295 | public void onStart() { |
1296 | - LOGD(TAG, "Syncing artists..."); |
1297 | + Log.d(TAG, "Syncing artists..."); |
1298 | + if (DIRECT_SQL) { |
1299 | + db = new MusicDatabase(SyncService.this).getWritableDatabase(); |
1300 | + db.beginTransaction(); |
1301 | + } |
1302 | progressBundle.putInt(EXTRA_LOADER_ID, R.id.artist_loader_id); |
1303 | } |
1304 | |
1305 | @Override |
1306 | public void onSuccess(U1Artist artist) { |
1307 | artistCount++; |
1308 | - ContentValues values = MusicContentValues.from(artist); |
1309 | - Uri artistUri = Artists.buildArtistUri(artist.getId()); |
1310 | - int count = mResolver.update(artistUri, values, null, null); |
1311 | - if (count == 0) { |
1312 | - mResolver.insert(Artists.CONTENT_URI, values); |
1313 | - } |
1314 | - // Insert artist albums. |
1315 | - ArrayList<ContentValues> albumsValues = MusicContentValues.albumsFrom(artist); |
1316 | - for (ContentValues albumValues : albumsValues) { |
1317 | - Uri artistAlbumUri = Artists.buildAlbumUri( |
1318 | - artist.getId(), albumValues.getAsString(Albums.ALBUM_ID)); |
1319 | - artistAlbumCount++; |
1320 | - int count2 = mResolver.update(artistAlbumUri, albumValues, null, null); |
1321 | - if (count2 == 0) { |
1322 | - mResolver.insert(artistAlbumUri, albumValues); |
1323 | - } |
1324 | + if (DIRECT_SQL) { |
1325 | + artistDao.updateOrInsert(db, artist); |
1326 | + } else { |
1327 | + artistDao.updateOrInsert(mResolver, artist); |
1328 | } |
1329 | mReceiver.send(SYNC_PROGRESS, progressBundle); |
1330 | } |
1331 | |
1332 | @Override |
1333 | public void onFailure(Failure failure) { |
1334 | - LOGE(TAG, String.format("Failed to get artists: %d -- %s", |
1335 | + this.failure = failure; |
1336 | + Log.e(TAG, String.format("Failed to get artists: %d -- %s", |
1337 | failure.getStatusCode(), failure.getMessage())); |
1338 | } |
1339 | |
1340 | @Override |
1341 | public void onFinish() { |
1342 | - LOGD(TAG, String.format("Finished syncing artists " + |
1343 | - "(got %d artists, %d artist albums).", artistCount, artistAlbumCount)); |
1344 | + if (DIRECT_SQL) { |
1345 | + if (failure == null) db.setTransactionSuccessful(); |
1346 | + db.endTransaction(); |
1347 | + db.close(); |
1348 | + } |
1349 | + Log.d(TAG, String.format("Finished syncing artists " + |
1350 | + "(got %d artists).", artistCount)); |
1351 | } |
1352 | }; |
1353 | |
1354 | private U1AlbumListener mAlbumListener = new U1AlbumListener() { |
1355 | + private SQLiteDatabase db; |
1356 | + private AlbumDao albumDao = new AlbumDao(); |
1357 | + private Bundle progressBundle = new Bundle(); |
1358 | + private Failure failure = null; |
1359 | private int albumCount = 0; |
1360 | |
1361 | - private Bundle progressBundle = new Bundle(); |
1362 | - |
1363 | @Override |
1364 | public void onStart() { |
1365 | - LOGD(TAG, "Syncing albums..."); |
1366 | + Log.d(TAG, "Syncing albums..."); |
1367 | + if (DIRECT_SQL) { |
1368 | + db = new MusicDatabase(SyncService.this).getWritableDatabase(); |
1369 | + db.beginTransaction(); |
1370 | + } |
1371 | progressBundle.putInt(EXTRA_LOADER_ID, R.id.album_loader_id); |
1372 | } |
1373 | |
1374 | @Override |
1375 | public void onSuccess(U1Album album) { |
1376 | albumCount++; |
1377 | - ContentValues values = MusicContentValues.from(album); |
1378 | - Uri albumUri = Albums.buildAlbumUri(album.getId()); |
1379 | - int count = mResolver.update(albumUri, values, null, null); |
1380 | - if (count == 0) { |
1381 | - mResolver.insert(Albums.CONTENT_URI, values); |
1382 | + if (DIRECT_SQL) { |
1383 | + albumDao.updateOrInsert(db, album); |
1384 | + } else { |
1385 | + albumDao.updateOrInsert(mResolver, album); |
1386 | } |
1387 | mReceiver.send(SYNC_PROGRESS, progressBundle); |
1388 | } |
1389 | |
1390 | @Override |
1391 | public void onFailure(Failure failure) { |
1392 | - super.onFailure(failure); |
1393 | - LOGE(TAG, String.format("Failed to get albums: %d -- %s", |
1394 | + this.failure = failure; |
1395 | + Log.e(TAG, String.format("Failed to get albums: %d -- %s", |
1396 | failure.getStatusCode(), failure.getMessage())); |
1397 | } |
1398 | |
1399 | @Override |
1400 | public void onFinish() { |
1401 | - LOGD(TAG, String.format("Finished syncing albums (got %s albums).", |
1402 | + if (DIRECT_SQL) { |
1403 | + if (failure == null) db.setTransactionSuccessful(); |
1404 | + db.endTransaction(); |
1405 | + db.close(); |
1406 | + } |
1407 | + Log.d(TAG, String.format("Finished syncing albums (got %s albums).", |
1408 | albumCount)); |
1409 | } |
1410 | }; |
1411 | |
1412 | private U1SongListener mSongListener = new U1SongListener() { |
1413 | + private SQLiteDatabase db; |
1414 | + private SongDao songDao = new SongDao(); |
1415 | + private GenreDao genreDao = new GenreDao(); |
1416 | + private Bundle progressBundle = new Bundle(); |
1417 | + private Failure failure = null; |
1418 | private int songCount = 0; |
1419 | |
1420 | - private Bundle progressBundle = new Bundle(); |
1421 | - |
1422 | @Override |
1423 | public void onStart() { |
1424 | - LOGD(TAG, "Syncing songs..."); |
1425 | + Log.d(TAG, "Syncing songs..."); |
1426 | + if (DIRECT_SQL) { |
1427 | + db = new MusicDatabase(SyncService.this).getWritableDatabase(); |
1428 | + db.beginTransaction(); |
1429 | + } |
1430 | progressBundle.putInt(EXTRA_LOADER_ID, R.id.song_loader_id); |
1431 | } |
1432 | |
1433 | @Override |
1434 | public void onSuccess(U1Song song) { |
1435 | songCount++; |
1436 | - ContentValues values = MusicContentValues.from(song); |
1437 | - Uri songUri = Songs.buildSongUri(song.getId()); |
1438 | - int count = mResolver.update(songUri, values, null, null); |
1439 | - if (count == 0) { |
1440 | - mResolver.insert(Songs.CONTENT_URI, values); |
1441 | + if (DIRECT_SQL) { |
1442 | + if (songDao.updateOrInsert(db, song)) { |
1443 | + genreDao.updateOrInsert(db, song.getGenre()); |
1444 | + } |
1445 | + } else { |
1446 | + songDao.updateOrInsert(mResolver, song); |
1447 | } |
1448 | mReceiver.send(SYNC_PROGRESS, progressBundle); |
1449 | } |
1450 | |
1451 | @Override |
1452 | public void onFailure(Failure failure) { |
1453 | - super.onFailure(failure); |
1454 | - LOGE(TAG, String.format("Failed to get songs: %d -- %s", |
1455 | + this.failure = failure; |
1456 | + Log.e(TAG, String.format("Failed to get songs: %d -- %s", |
1457 | failure.getStatusCode(), failure.getMessage())); |
1458 | } |
1459 | |
1460 | @Override |
1461 | public void onFinish() { |
1462 | - LOGD(TAG, String.format("Finished syncing songs (got %d songs).", |
1463 | + if (DIRECT_SQL) { |
1464 | + if (failure == null) db.setTransactionSuccessful(); |
1465 | + db.endTransaction(); |
1466 | + db.close(); |
1467 | + } |
1468 | + Log.d(TAG, String.format("Finished syncing songs (got %d songs).", |
1469 | songCount)); |
1470 | } |
1471 | }; |
1472 | |
1473 | private U1PlaylistListener mPlaylistListener = new U1PlaylistListener() { |
1474 | + private SQLiteDatabase db; |
1475 | + private PlaylistDao playlistDao = new PlaylistDao(); |
1476 | + private Bundle progressBundle = new Bundle(); |
1477 | + private Failure failure = null; |
1478 | private int playlistCount = 0; |
1479 | |
1480 | - private Bundle progressBundle = new Bundle(); |
1481 | - |
1482 | @Override |
1483 | public void onStart() { |
1484 | - LOGD(TAG, "Syncing playlists..."); |
1485 | + Log.d(TAG, "Syncing playlists..."); |
1486 | + if (DIRECT_SQL) { |
1487 | + db = new MusicDatabase(SyncService.this).getWritableDatabase(); |
1488 | + db.beginTransaction(); |
1489 | + } |
1490 | progressBundle.putInt(EXTRA_LOADER_ID, R.id.playlist_loader_id); |
1491 | } |
1492 | |
1493 | @Override |
1494 | public void onSuccess(U1Playlist playlist) { |
1495 | playlistCount++; |
1496 | - ContentValues values = MusicContentValues.from(playlist); |
1497 | - Uri playlistUri = Playlists.buildPlaylistUri(playlist.getId()); |
1498 | - int count = mResolver.update(playlistUri, values, null, null); |
1499 | - if (count == 0) { |
1500 | - mResolver.insert(Playlists.CONTENT_URI, values); |
1501 | + if (DIRECT_SQL) { |
1502 | + playlistDao.updateOrInsert(db, playlist); |
1503 | + } else { |
1504 | + playlistDao.updateOrInsert(mResolver, playlist); |
1505 | } |
1506 | mReceiver.send(SYNC_PROGRESS, progressBundle); |
1507 | } |
1508 | |
1509 | @Override |
1510 | public void onFailure(Failure failure) { |
1511 | - super.onFailure(failure); |
1512 | - LOGE(TAG, String.format("Failed to get playlists: %d -- %s", |
1513 | + this.failure = failure; |
1514 | + Log.e(TAG, String.format("Failed to get playlists: %d -- %s", |
1515 | failure.getStatusCode(), failure.getMessage())); |
1516 | } |
1517 | |
1518 | @Override |
1519 | public void onFinish() { |
1520 | - LOGD(TAG, String.format("Finished syncing playlists (got %d playlists).", |
1521 | + if (DIRECT_SQL) { |
1522 | + if (failure == null) db.setTransactionSuccessful(); |
1523 | + db.endTransaction(); |
1524 | + db.close(); |
1525 | + } |
1526 | + Log.d(TAG, String.format("Finished syncing playlists (got %d playlists).", |
1527 | playlistCount)); |
1528 | } |
1529 | }; |
1530 | @@ -330,35 +377,46 @@ |
1531 | } |
1532 | |
1533 | private PlaylistSongListener mPlaylistSongListener = new PlaylistSongListener() { |
1534 | + private SQLiteDatabase db; |
1535 | + private PlaylistSongDao playlistSongDao = new PlaylistSongDao(); |
1536 | + private Failure failure = null; |
1537 | private int playlistSongCount = 0; |
1538 | |
1539 | @Override |
1540 | public void onStart() { |
1541 | playlistSongCount = 0; // This listener is reused, so reset. |
1542 | - LOGD(TAG, "Syncing playlist songs..."); |
1543 | + Log.d(TAG, "Syncing playlist songs..."); |
1544 | + if (DIRECT_SQL) { |
1545 | + db = new MusicDatabase(SyncService.this).getWritableDatabase(); |
1546 | + db.beginTransaction(); |
1547 | + } |
1548 | } |
1549 | |
1550 | @Override |
1551 | public void onSuccess(U1Song song) { |
1552 | playlistSongCount++; |
1553 | - ContentValues values = MusicContentValues.from(mPlaylistId, song.getId()); |
1554 | - Uri playlistSongsUri = Playlists.buildPlaylistSongUri(mPlaylistId, song.getId()); |
1555 | - int count = mResolver.update(playlistSongsUri, values, null, null); |
1556 | - if (count == 0) { |
1557 | - mResolver.insert(playlistSongsUri, values); |
1558 | + if (DIRECT_SQL) { |
1559 | + playlistSongDao.updateOrInsert(db, mPlaylistId, song.getId()); |
1560 | + } else { |
1561 | + playlistSongDao.updateOrInsert(mResolver, mPlaylistId, song); |
1562 | } |
1563 | } |
1564 | |
1565 | @Override |
1566 | public void onFailure(Failure failure) { |
1567 | - super.onFailure(failure); |
1568 | - LOGE(TAG, String.format("Failed to get playlist songs: %d -- %s", |
1569 | + this.failure = failure; |
1570 | + Log.e(TAG, String.format("Failed to get playlist songs: %d -- %s", |
1571 | failure.getStatusCode(), failure.getMessage())); |
1572 | } |
1573 | |
1574 | @Override |
1575 | public void onFinish() { |
1576 | - LOGD(TAG, String.format("Finished syncing playlist songs (got %s playlist songs).", |
1577 | + if (DIRECT_SQL) { |
1578 | + if (failure == null) db.setTransactionSuccessful(); |
1579 | + db.endTransaction(); |
1580 | + db.close(); |
1581 | + } |
1582 | + Log.d(TAG, String.format("Finished syncing playlist songs (got %s playlist songs).", |
1583 | playlistSongCount)); |
1584 | } |
1585 | }; |
1586 | |
1587 | === modified file 'src/com/ubuntuone/android/music/ui/HomeActivity.java' |
1588 | --- src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-08 14:14:54 +0000 |
1589 | +++ src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-21 17:34:22 +0000 |
1590 | @@ -192,7 +192,7 @@ |
1591 | mService.register(HomeActivity.this); |
1592 | } |
1593 | }; |
1594 | - if (UbuntuOneMusic.DEBUG_SHOULD_BIND) { |
1595 | + if (UbuntuOneMusic.SHOULD_BIND) { |
1596 | bindService(service, mConn, BIND_AUTO_CREATE | BIND_IMPORTANT); |
1597 | } |
1598 | |
1599 | |
1600 | === added file 'test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java' |
1601 | --- test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java 1970-01-01 00:00:00 +0000 |
1602 | +++ test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java 2012-11-21 17:34:22 +0000 |
1603 | @@ -0,0 +1,10 @@ |
1604 | +package com.ubuntuone.android.music; |
1605 | + |
1606 | +import junit.framework.TestCase; |
1607 | + |
1608 | +public class UbuntuOneMusicTest extends TestCase |
1609 | +{ |
1610 | + public void testIsReleaseVersion() { |
1611 | + assertTrue("NOT a release version!", UbuntuOneMusic.IS_RELEASE); |
1612 | + } |
1613 | +} |
1614 | |
1615 | === modified file 'test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java' |
1616 | --- test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java 2012-11-13 13:58:31 +0000 |
1617 | +++ test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java 2012-11-21 17:34:22 +0000 |
1618 | @@ -39,7 +39,7 @@ |
1619 | |
1620 | final U1Artist u1Artist = new U1Artist(id, artistUrl, artist, |
1621 | artistArtUrl, albumList, songCount); |
1622 | - final ContentValues cv = MusicContentValues.from(u1Artist); |
1623 | + final ContentValues cv = MusicContentValues.forArtist(u1Artist); |
1624 | |
1625 | assertEquals(id, cv.getAsString(Artists.ARTIST_ID)); |
1626 | assertEquals(artist, cv.getAsString(Artists.ARTIST_NAME)); |
1627 | @@ -63,7 +63,7 @@ |
1628 | |
1629 | final U1Album u1Album = new U1Album(id, albumUrl, artist, artistId, |
1630 | title, dateAdded, albumArtUrl, year); |
1631 | - final ContentValues cv = MusicContentValues.from(u1Album); |
1632 | + final ContentValues cv = MusicContentValues.forAlbum(u1Album); |
1633 | |
1634 | assertEquals(id, cv.getAsString(Albums.ALBUM_ID)); |
1635 | assertEquals(title, cv.getAsString(Albums.ALBUM_TITLE)); |
1636 | @@ -84,7 +84,7 @@ |
1637 | final String albumId = HashUtils.md5(title+artist); |
1638 | final String artistId = HashUtils.md5(artist); |
1639 | final String genre = "Dubstep"; |
1640 | - final String genreIds = HashUtils.md5(genre.toUpperCase()); |
1641 | + final String genreIds = MusicContentValues.getGenreId(genre); |
1642 | final Integer year = 2012; |
1643 | final Integer discNumber = 1; |
1644 | final Integer track = 9; |
1645 | @@ -105,7 +105,7 @@ |
1646 | album, songArtUrl, genre, year, discNumber, track, |
1647 | duration, size, bitRate, artist, artistId, title, suffix, |
1648 | contentType, songStreamUrl, path); |
1649 | - final ContentValues cv = MusicContentValues.from(u1Song); |
1650 | + final ContentValues cv = MusicContentValues.forSong(u1Song); |
1651 | |
1652 | assertEquals(id, cv.getAsString(Songs.SONG_ID)); |
1653 | assertEquals(title, cv.getAsString(Songs.SONG_TITLE)); |
1654 | @@ -141,7 +141,7 @@ |
1655 | |
1656 | final U1Playlist u1Playlist = new U1Playlist( |
1657 | id, playlistUrl, name, songCount); |
1658 | - final ContentValues cv = MusicContentValues.from(u1Playlist); |
1659 | + final ContentValues cv = MusicContentValues.forPlaylist(u1Playlist); |
1660 | |
1661 | assertEquals(id, cv.getAsString(Playlists.PLAYLIST_ID)); |
1662 | assertEquals(name, cv.getAsString(Playlists.PLAYLIST_NAME)); |
1663 | @@ -153,7 +153,7 @@ |
1664 | final String playlistId = "bc54b75b-0632-4438-b6a3-c90b83362562"; |
1665 | final String songId ="i6aVaQDYSS6Pal0GbO4MAw"; |
1666 | |
1667 | - final ContentValues cv = MusicContentValues.from(playlistId, songId); |
1668 | + final ContentValues cv = MusicContentValues.forPlaylistSong(playlistId, songId); |
1669 | |
1670 | assertEquals(playlistId, cv.getAsString(PlaylistSongs.PLAYLIST_ID)); |
1671 | assertEquals(songId, cv.getAsString(PlaylistSongs.SONG_ID)); |
1672 | @@ -161,9 +161,9 @@ |
1673 | |
1674 | public void testFromGenre() { |
1675 | final String genre = "Drum'n'Base"; |
1676 | - final String genreId = HashUtils.md5(genre.toUpperCase()); |
1677 | + final String genreId = MusicContentValues.getGenreId(genre); |
1678 | |
1679 | - final ContentValues cv = MusicContentValues.fromGenre(genre); |
1680 | + final ContentValues cv = MusicContentValues.forGenre(genre); |
1681 | |
1682 | assertEquals(genreId, cv.getAsString(Genres.GENRE_ID)); |
1683 | assertEquals(genre, cv.getAsString(Genres.GENRE_TITLE)); |
1684 | |
1685 | === modified file 'test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java' |
1686 | --- test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-13 13:58:31 +0000 |
1687 | +++ test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-21 17:34:22 +0000 |
1688 | @@ -4,6 +4,7 @@ |
1689 | |
1690 | import android.content.ContentValues; |
1691 | import android.database.Cursor; |
1692 | +import android.database.sqlite.SQLiteDatabase; |
1693 | import android.net.Uri; |
1694 | |
1695 | import com.ubuntuone.android.music.provider.MusicContract.Albums; |
1696 | @@ -13,6 +14,12 @@ |
1697 | import com.ubuntuone.android.music.provider.MusicContract.Playlists; |
1698 | import com.ubuntuone.android.music.provider.MusicContract.Songs; |
1699 | import com.ubuntuone.android.music.provider.MusicContract.SongsColumns; |
1700 | +import com.ubuntuone.android.music.provider.dao.AlbumDao; |
1701 | +import com.ubuntuone.android.music.provider.dao.ArtistDao; |
1702 | +import com.ubuntuone.android.music.provider.dao.GenreDao; |
1703 | +import com.ubuntuone.android.music.provider.dao.PlaylistDao; |
1704 | +import com.ubuntuone.android.music.provider.dao.PlaylistSongDao; |
1705 | +import com.ubuntuone.android.music.provider.dao.SongDao; |
1706 | import com.ubuntuone.android.music.util.HashUtils; |
1707 | import com.ubuntuone.android.music.util.Lists; |
1708 | import com.ubuntuone.api.music.model.U1Album; |
1709 | @@ -32,7 +39,7 @@ |
1710 | albumList.add("album6-album_id"); |
1711 | U1Artist artist = new U1Artist("artist3-artist_id", "artist3-artist_url", |
1712 | "artist3-artist_name", "artist3-artist_art_url", albumList, 42); |
1713 | - ContentValues cv = MusicContentValues.from(artist); |
1714 | + ContentValues cv = MusicContentValues.forArtist(artist); |
1715 | |
1716 | Uri uri = mResolver.insert(Artists.CONTENT_URI, cv); |
1717 | |
1718 | @@ -42,13 +49,42 @@ |
1719 | assertEquals("Wrong artist row count returned.", 1, cursor.getCount()); |
1720 | assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1721 | |
1722 | - assertEquals("Wrong artist id.", "artist3-artist_id", |
1723 | - cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID))); |
1724 | - assertEquals("Wrong artist name.", "artist3-artist_name", |
1725 | - cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME))); |
1726 | - assertEquals("Wrong artist album.", "album5-album_id,album6-album_id", |
1727 | - cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST))); |
1728 | - assertEquals("Wrong artist song count.", 42, |
1729 | + assertEquals("Wrong artist id.", artist.getId(), |
1730 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID))); |
1731 | + assertEquals("Wrong artist name.", artist.getArtist(), |
1732 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME))); |
1733 | + assertEquals("Wrong artist album.", MusicContentValues.getAlbumList(artist), |
1734 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST))); |
1735 | + assertEquals("Wrong artist song count.", (int) artist.getSongCount(), |
1736 | + cursor.getInt(cursor.getColumnIndexOrThrow(Artists.SONG_COUNT))); |
1737 | + |
1738 | + cursor.close(); |
1739 | + } |
1740 | + |
1741 | + public void testArtistDaoInsert() { |
1742 | + ArrayList<String> albumList = Lists.newArrayList(); |
1743 | + albumList.add("album5-album_id"); |
1744 | + albumList.add("album6-album_id"); |
1745 | + U1Artist artist = new U1Artist("artist3-artist_id", "artist3-artist_url", |
1746 | + "artist3-artist_name", "artist3-artist_art_url", albumList, 42); |
1747 | + ArtistDao artistDao = new ArtistDao(); |
1748 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
1749 | + artistDao.updateOrInsert(db, artist); |
1750 | + db.close(); |
1751 | + |
1752 | + Uri uri = Artists.buildArtistUri(artist.getId()); |
1753 | + |
1754 | + Cursor cursor = mResolver.query(uri, Artists.DEFAULT_PROJECTION, null, null, null); |
1755 | + assertEquals("Wrong artist row count returned.", 1, cursor.getCount()); |
1756 | + assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1757 | + |
1758 | + assertEquals("Wrong artist id.", artist.getId(), |
1759 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID))); |
1760 | + assertEquals("Wrong artist name.", artist.getArtist(), |
1761 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME))); |
1762 | + assertEquals("Wrong artist album.", MusicContentValues.getAlbumList(artist), |
1763 | + cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST))); |
1764 | + assertEquals("Wrong artist song count.", (int) artist.getSongCount(), |
1765 | cursor.getInt(cursor.getColumnIndexOrThrow(Artists.SONG_COUNT))); |
1766 | |
1767 | cursor.close(); |
1768 | @@ -57,7 +93,7 @@ |
1769 | public void testAlbumsInsert() { |
1770 | U1Album album = new U1Album("album5-album_id", "album5-album_url", "artist1-artist_name", |
1771 | "artist1-artist_id", "album5-album_title", 1345345345L, "album5-art-url", 2012); |
1772 | - ContentValues cv = MusicContentValues.from(album); |
1773 | + ContentValues cv = MusicContentValues.forAlbum(album); |
1774 | |
1775 | Uri uri = mResolver.insert(Albums.CONTENT_URI, cv); |
1776 | |
1777 | @@ -67,18 +103,47 @@ |
1778 | assertEquals("Wrong album row count returned.", 1, cursor.getCount()); |
1779 | assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1780 | |
1781 | - assertEquals("Wrong album id.", "album5-album_id", |
1782 | - cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID))); |
1783 | - assertEquals("Wrong album title.", "album5-album_title", |
1784 | - cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE))); |
1785 | - assertEquals("Wrong album artist name.", "artist1-artist_name", |
1786 | - cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST))); |
1787 | - assertEquals("Wrong album artist id.", |
1788 | - HashUtils.md5("artist1-artist_name"), |
1789 | - cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID))); |
1790 | - assertEquals("Wrong album year.", 2012, |
1791 | - cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR))); |
1792 | - assertEquals("Wrong album date added.", 1345345345L, |
1793 | + assertEquals("Wrong album id.", album.getId(), |
1794 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID))); |
1795 | + assertEquals("Wrong album title.", album.getTitle(), |
1796 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE))); |
1797 | + assertEquals("Wrong album artist name.", album.getArtist(), |
1798 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST))); |
1799 | + assertEquals("Wrong album artist id.", album.getArtistId(), |
1800 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID))); |
1801 | + assertEquals("Wrong album year.", (int) album.getYear(), |
1802 | + cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR))); |
1803 | + assertEquals("Wrong album date added.", (long) album.getParsedDate(), |
1804 | + cursor.getLong(cursor.getColumnIndexOrThrow(Albums.ALBUM_DATE_ADDED))); |
1805 | + |
1806 | + cursor.close(); |
1807 | + } |
1808 | + |
1809 | + public void testAlbumDaoInsert() { |
1810 | + U1Album album = new U1Album("album5-album_id", "album5-album_url", "artist1-artist_name", |
1811 | + "artist1-artist_id", "album5-album_title", 1345345345L, "album5-art-url", 2012); |
1812 | + AlbumDao albumDao = new AlbumDao(); |
1813 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
1814 | + albumDao.updateOrInsert(db, album); |
1815 | + db.close(); |
1816 | + |
1817 | + Uri uri = Albums.buildAlbumUri(album.getId()); |
1818 | + |
1819 | + Cursor cursor = mResolver.query(uri, Albums.DEFAULT_PROJECTION, null, null, null); |
1820 | + assertEquals("Wrong album row count returned.", 1, cursor.getCount()); |
1821 | + assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1822 | + |
1823 | + assertEquals("Wrong album id.", album.getId(), |
1824 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID))); |
1825 | + assertEquals("Wrong album title.", album.getTitle(), |
1826 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE))); |
1827 | + assertEquals("Wrong album artist name.", album.getArtist(), |
1828 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST))); |
1829 | + assertEquals("Wrong album artist id.", album.getArtistId(), |
1830 | + cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID))); |
1831 | + assertEquals("Wrong album year.", (int) album.getYear(), |
1832 | + cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR))); |
1833 | + assertEquals("Wrong album date added.", (long) album.getParsedDate(), |
1834 | cursor.getLong(cursor.getColumnIndexOrThrow(Albums.ALBUM_DATE_ADDED))); |
1835 | |
1836 | cursor.close(); |
1837 | @@ -88,9 +153,9 @@ |
1838 | U1Song song = new U1Song("song5-song_id", "song5-song_url", |
1839 | HashUtils.md5("album1-album_titleartist1-artist_name"), "song5-album_artist", |
1840 | "album1-album_title", "song5-song_art_url", "genre2", 2009, 3, 2, 315, |
1841 | - 1024 * 1024 * 2, 256, "artist1-artist_name", "aritst1-artist_id", |
1842 | + 1024 * 1024 * 2, 256, "artist1-artist_name", HashUtils.md5("artist1-artist_name"), |
1843 | "song5-song_title", "mp3", "audio/mpeg", "song5-song_stream", null); |
1844 | - ContentValues cv = MusicContentValues.from(song); |
1845 | + ContentValues cv = MusicContentValues.forSong(song); |
1846 | |
1847 | Uri uri = mResolver.insert(Songs.CONTENT_URI, cv); |
1848 | |
1849 | @@ -100,40 +165,96 @@ |
1850 | assertEquals("Wrong song row count returned.", 1, cursor.getCount()); |
1851 | assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1852 | |
1853 | - assertEquals("Wrong song id.", "song5-song_id", |
1854 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID))); |
1855 | - assertEquals("Wrong song title.", "song5-song_title", |
1856 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE))); |
1857 | - assertEquals("Wrong song album.", "album1-album_title", |
1858 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM))); |
1859 | - assertEquals("Wrong song album id.", |
1860 | - HashUtils.md5("album1-album_titleartist1-artist_name"), |
1861 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID))); |
1862 | - assertEquals("Wrong song album artist.", "song5-album_artist", |
1863 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST))); |
1864 | - assertEquals("Wrong song artist.", "artist1-artist_name", |
1865 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST))); |
1866 | - assertEquals("Wrong song artist id.", HashUtils.md5("artist1-artist_name"), |
1867 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID))); |
1868 | - assertEquals("Wrong song genre.", "genre2", |
1869 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE))); |
1870 | - assertEquals("Wrong song genre ids.", HashUtils.md5("genre2".toUpperCase()), |
1871 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID))); |
1872 | - assertEquals("Wrong song year.", 2009, |
1873 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR))); |
1874 | - assertEquals("Wrong song disc number.", 3, |
1875 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER))); |
1876 | - assertEquals("Wrong song track.", 2, |
1877 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK))); |
1878 | - assertEquals("Wrong song duration.", 315, |
1879 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION))); |
1880 | - assertEquals("Wrong song size.", 1024 * 1024 * 2, |
1881 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE))); |
1882 | - assertEquals("Wrong song bit rate.", 256, |
1883 | - cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE))); |
1884 | - assertEquals("Wrong song suffix.", "mp3", |
1885 | - cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX))); |
1886 | - assertEquals("Wrong song content type.", "audio/mpeg", |
1887 | + assertEquals("Wrong song id.", song.getId(), |
1888 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID))); |
1889 | + assertEquals("Wrong song title.", song.getTitle(), |
1890 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE))); |
1891 | + assertEquals("Wrong song album.", song.getAlbum(), |
1892 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM))); |
1893 | + assertEquals("Wrong song album id.", song.getAlbumId(), |
1894 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID))); |
1895 | + assertEquals("Wrong song album artist.", song.getAlbumArtist(), |
1896 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST))); |
1897 | + assertEquals("Wrong song artist.", song.getArtist(), |
1898 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST))); |
1899 | + assertEquals("Wrong song artist id.", song.getArtistId(), |
1900 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID))); |
1901 | + assertEquals("Wrong song genre.", song.getGenre(), |
1902 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE))); |
1903 | + assertEquals("Wrong song genre ids.", MusicContentValues.getGenreId(song.getGenre()), |
1904 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID))); |
1905 | + assertEquals("Wrong song year.", (int) song.getYear(), |
1906 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR))); |
1907 | + assertEquals("Wrong song disc number.", (int) song.getDiscNumber(), |
1908 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER))); |
1909 | + assertEquals("Wrong song track.", (int) song.getTrack(), |
1910 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK))); |
1911 | + assertEquals("Wrong song duration.", (int) song.getDuration(), |
1912 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION))); |
1913 | + assertEquals("Wrong song size.", (int) song.getSize(), |
1914 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE))); |
1915 | + assertEquals("Wrong song bit rate.", (int) song.getBitRate(), |
1916 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE))); |
1917 | + assertEquals("Wrong song suffix.", song.getSuffix(), |
1918 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX))); |
1919 | + assertEquals("Wrong song content type.", song.getContentType(), |
1920 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_CONTENT_TYPE))); |
1921 | + assertEquals("Wrong song last played at.", 0L, |
1922 | + cursor.getLong(cursor.getColumnIndexOrThrow(Songs.SONG_LAST_PLAYED_AT))); |
1923 | + |
1924 | + cursor.close(); |
1925 | + } |
1926 | + |
1927 | + public void testSongDaoInsert() { |
1928 | + U1Song song = new U1Song("song5-song_id", "song5-song_url", |
1929 | + HashUtils.md5("album1-album_titleartist1-artist_name"), "song5-album_artist", |
1930 | + "album1-album_title", "song5-song_art_url", "genre2", 2009, 3, 2, 315, |
1931 | + 1024 * 1024 * 2, 256, "artist1-artist_name", HashUtils.md5("artist1-artist_name"), |
1932 | + "song5-song_title", "mp3", "audio/mpeg", "song5-song_stream", null); |
1933 | + SongDao songDao = new SongDao(); |
1934 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
1935 | + songDao.updateOrInsert(db, song); |
1936 | + db.close(); |
1937 | + |
1938 | + Uri uri = Songs.buildSongUri(song.getId()); |
1939 | + |
1940 | + Cursor cursor = mResolver.query(uri, Songs.DEFAULT_PROJECTION, null, null, null); |
1941 | + assertEquals("Wrong song row count returned.", 1, cursor.getCount()); |
1942 | + assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1943 | + |
1944 | + assertEquals("Wrong song id.", song.getId(), |
1945 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID))); |
1946 | + assertEquals("Wrong song title.", song.getTitle(), |
1947 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE))); |
1948 | + assertEquals("Wrong song album.", song.getAlbum(), |
1949 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM))); |
1950 | + assertEquals("Wrong song album id.", song.getAlbumId(), |
1951 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID))); |
1952 | + assertEquals("Wrong song album artist.", song.getAlbumArtist(), |
1953 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST))); |
1954 | + assertEquals("Wrong song artist.", song.getArtist(), |
1955 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST))); |
1956 | + assertEquals("Wrong song artist id.", song.getArtistId(), |
1957 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID))); |
1958 | + assertEquals("Wrong song genre.", song.getGenre(), |
1959 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE))); |
1960 | + assertEquals("Wrong song genre ids.", MusicContentValues.getGenreId(song.getGenre()), |
1961 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID))); |
1962 | + assertEquals("Wrong song year.", (int) song.getYear(), |
1963 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR))); |
1964 | + assertEquals("Wrong song disc number.", (int) song.getDiscNumber(), |
1965 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER))); |
1966 | + assertEquals("Wrong song track.", (int) song.getTrack(), |
1967 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK))); |
1968 | + assertEquals("Wrong song duration.", (int) song.getDuration(), |
1969 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION))); |
1970 | + assertEquals("Wrong song size.", (int) song.getSize(), |
1971 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE))); |
1972 | + assertEquals("Wrong song bit rate.", (int) song.getBitRate(), |
1973 | + cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE))); |
1974 | + assertEquals("Wrong song suffix.", song.getSuffix(), |
1975 | + cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX))); |
1976 | + assertEquals("Wrong song content type.", song.getContentType(), |
1977 | cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_CONTENT_TYPE))); |
1978 | assertEquals("Wrong song last played at.", 0L, |
1979 | cursor.getLong(cursor.getColumnIndexOrThrow(Songs.SONG_LAST_PLAYED_AT))); |
1980 | @@ -144,7 +265,7 @@ |
1981 | public void testPlaylistsInsert() { |
1982 | U1Playlist playlist = new U1Playlist("playlist3-playlist_id", "playlist3-playlist_url", |
1983 | "playlist3-playlist_name", 10); |
1984 | - ContentValues cv = MusicContentValues.from(playlist); |
1985 | + ContentValues cv = MusicContentValues.forPlaylist(playlist); |
1986 | |
1987 | Uri uri = mResolver.insert(Playlists.CONTENT_URI, cv); |
1988 | |
1989 | @@ -154,18 +275,44 @@ |
1990 | assertEquals("Wrong playlist row count returned.", 1, cursor.getCount()); |
1991 | assertTrue("Cursor missing rows.", cursor.moveToNext()); |
1992 | |
1993 | - assertEquals("Wrong playlist id.", "playlist3-playlist_id", |
1994 | - cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID))); |
1995 | - assertEquals("Wrong playlist name.", "playlist3-playlist_name", |
1996 | - cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME))); |
1997 | - assertEquals("Wrong playlist song count.", 10, |
1998 | + assertEquals("Wrong playlist id.", playlist.getId(), |
1999 | + cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID))); |
2000 | + assertEquals("Wrong playlist name.", playlist.getName(), |
2001 | + cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME))); |
2002 | + assertEquals("Wrong playlist song count.", (int) playlist.getSongCount(), |
2003 | + cursor.getInt(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_SONG_COUNT))); |
2004 | + |
2005 | + cursor.close(); |
2006 | + } |
2007 | + |
2008 | + public void testPlaylistDaoInsert() { |
2009 | + U1Playlist playlist = new U1Playlist("playlist3-playlist_id", "playlist3-playlist_url", |
2010 | + "playlist3-playlist_name", 10); |
2011 | + PlaylistDao playlistDao = new PlaylistDao(); |
2012 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
2013 | + playlistDao.updateOrInsert(db, playlist); |
2014 | + db.close(); |
2015 | + |
2016 | + Uri uri = Playlists.buildPlaylistUri(playlist.getId()); |
2017 | + |
2018 | + Cursor cursor = mResolver.query(uri, Playlists.DEFAULT_PROJECTION, null, null, null); |
2019 | + assertEquals("Wrong playlist row count returned.", 1, cursor.getCount()); |
2020 | + assertTrue("Cursor missing rows.", cursor.moveToNext()); |
2021 | + |
2022 | + assertEquals("Wrong playlist id.", playlist.getId(), |
2023 | + cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID))); |
2024 | + assertEquals("Wrong playlist name.", playlist.getName(), |
2025 | + cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME))); |
2026 | + assertEquals("Wrong playlist song count.", (int) playlist.getSongCount(), |
2027 | cursor.getInt(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_SONG_COUNT))); |
2028 | |
2029 | cursor.close(); |
2030 | } |
2031 | |
2032 | public void testPlaylistSongsInsert() { |
2033 | - Uri playlistSongsUri = Playlists.buildPlaylistSongsUri("playlist1-playlist_id"); |
2034 | + final String playlistId = "playlist1-playlist_id"; |
2035 | + final String songId = "song3-song_id"; |
2036 | + Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId); |
2037 | |
2038 | { // Check preconditions. |
2039 | Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION, |
2040 | @@ -175,7 +322,7 @@ |
2041 | } |
2042 | |
2043 | // Insert new song. |
2044 | - ContentValues cv = MusicContentValues.from("playlist1-playlist_id", "song3-song_id"); |
2045 | + ContentValues cv = MusicContentValues.forPlaylistSong(playlistId, songId); |
2046 | Uri uri = mResolver.insert(playlistSongsUri, cv); |
2047 | |
2048 | assertNotNull("Inserted playlist song uri is null.", uri); |
2049 | @@ -186,9 +333,41 @@ |
2050 | |
2051 | assertTrue("Cursor missing rows.", cursor.moveToPosition(2)); // move to third song |
2052 | |
2053 | - assertEquals("Wrong playlist id.", "playlist1-playlist_id", |
2054 | - cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID))); |
2055 | - assertEquals("Wrong playlist song id.", "song3-song_id", |
2056 | + assertEquals("Wrong playlist id.", playlistId, |
2057 | + cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID))); |
2058 | + assertEquals("Wrong playlist song id.", songId, |
2059 | + cursor.getString(cursor.getColumnIndexOrThrow(SongsColumns.SONG_ID))); |
2060 | + |
2061 | + cursor.close(); |
2062 | + } |
2063 | + |
2064 | + public void testPlaylistSongDaoInsert() { |
2065 | + final String playlistId = "playlist1-playlist_id"; |
2066 | + final String songId = "song3-song_id"; |
2067 | + Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId); |
2068 | + |
2069 | + { // Check preconditions. |
2070 | + Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION, |
2071 | + null, null, PlaylistSongs.DEFAULT_SORT); |
2072 | + assertEquals("Wrong playlist song row count returned.", 2, cursor.getCount()); |
2073 | + cursor.close(); |
2074 | + } |
2075 | + |
2076 | + // Insert new song. |
2077 | + PlaylistSongDao playlistSongDao = new PlaylistSongDao(); |
2078 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
2079 | + playlistSongDao.updateOrInsert(db, playlistId, songId); |
2080 | + db.close(); |
2081 | + |
2082 | + Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION, |
2083 | + null, null, PlaylistSongs.DEFAULT_SORT); |
2084 | + assertEquals("Wrong playlist song row count returned.", 3, cursor.getCount()); |
2085 | + |
2086 | + assertTrue("Cursor missing rows.", cursor.moveToPosition(2)); // move to third song |
2087 | + |
2088 | + assertEquals("Wrong playlist id.", playlistId, |
2089 | + cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID))); |
2090 | + assertEquals("Wrong playlist song id.", songId, |
2091 | cursor.getString(cursor.getColumnIndexOrThrow(SongsColumns.SONG_ID))); |
2092 | |
2093 | cursor.close(); |
2094 | @@ -199,11 +378,11 @@ |
2095 | String genre1 = "acid jazz"; |
2096 | String genre2 = "Acid JAZZ"; |
2097 | |
2098 | - ContentValues cv1 = MusicContentValues.fromGenre(genre1); |
2099 | + ContentValues cv1 = MusicContentValues.forGenre(genre1); |
2100 | Uri uri = mResolver.insert(Genres.CONTENT_URI, cv1); |
2101 | assertNotNull("Inserted genre uri is null.", uri); |
2102 | |
2103 | - ContentValues cv2 = MusicContentValues.fromGenre(genre2); |
2104 | + ContentValues cv2 = MusicContentValues.forGenre(genre2); |
2105 | Uri uri2 = mResolver.insert(Genres.CONTENT_URI, cv2); |
2106 | assertNotNull("Inserted genre uri is null.", uri2); |
2107 | |
2108 | @@ -213,7 +392,28 @@ |
2109 | assertEquals("Wrong genre row count returned.", 1, cursor.getCount()); |
2110 | assertTrue("Cursor missing rows.", cursor.moveToNext()); |
2111 | |
2112 | - assertEquals("Wrong genre name.", "acid jazz", |
2113 | + assertEquals("Wrong genre name.", genre1, |
2114 | + cursor.getString(cursor.getColumnIndexOrThrow(Genres.GENRE_TITLE))); |
2115 | + } |
2116 | + |
2117 | + public void testGenreDaoInsert() { |
2118 | + // These genres are treated as same: md5(genre.toUpperCase()) |
2119 | + String genre1 = "acid jazz"; |
2120 | + String genre2 = "Acid JAZZ"; |
2121 | + |
2122 | + GenreDao genreDao = new GenreDao(); |
2123 | + SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase(); |
2124 | + genreDao.updateOrInsert(db, genre1); |
2125 | + genreDao.updateOrInsert(db, genre2); |
2126 | + db.close(); |
2127 | + |
2128 | + Cursor cursor = mResolver.query(Genres.CONTENT_URI, |
2129 | + Genres.DEFAULT_PROJECTION, null, null, null); |
2130 | + |
2131 | + assertEquals("Wrong genre row count returned.", 1, cursor.getCount()); |
2132 | + assertTrue("Cursor missing rows.", cursor.moveToNext()); |
2133 | + |
2134 | + assertEquals("Wrong genre name.", genre1, |
2135 | cursor.getString(cursor.getColumnIndexOrThrow(Genres.GENRE_TITLE))); |
2136 | } |
2137 | } |