Merge lp:~ubuntuone-client-engineering/ubuntuone-android-music/metadata-caching-optimisation into lp:ubuntuone-android-music/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
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
=== modified file 'src/com/ubuntuone/android/music/UbuntuOneMusic.java'
--- src/com/ubuntuone/android/music/UbuntuOneMusic.java 2012-11-13 13:58:31 +0000
+++ src/com/ubuntuone/android/music/UbuntuOneMusic.java 2012-11-21 17:34:22 +0000
@@ -45,11 +45,20 @@
45{45{
46 public static final String TAG = UbuntuOneMusic.class.getSimpleName();46 public static final String TAG = UbuntuOneMusic.class.getSimpleName();
47 47
48 public static final boolean DEBUG_SHOULD_SYNC = true;48 /** Should always be true. False would indicate a debug build. */
49 public static final boolean DEBUG_SHOULD_BIND = true;49 public static final boolean IS_RELEASE = true; // Never commit false.
50 public static final boolean DEBUG_SHOULD_PLAY = true;50
51 // Following flags have been introduced to ease proper test suite runs and debugging.
52
53 /** Debug flag indicating if the app should attempt metadata sync. */
54 public static final boolean SHOULD_SYNC = IS_RELEASE;
55 /** Debug flag indicating if the app should bind to {@link MusicService}. */
56 public static final boolean SHOULD_BIND = IS_RELEASE;
57 /** Debug flag indicating if the app should actually playback music. */
58 public static final boolean SHOULD_PLAY = IS_RELEASE;
59
51 // Set this to true to enable foreign key constraint enforcing.60 // Set this to true to enable foreign key constraint enforcing.
52 public static final boolean DEBUG_SHOULD_USE_FK = false;61 public static final boolean SHOULD_USE_FK = true;
53 62
54 private static UbuntuOneMusic instance;63 private static UbuntuOneMusic instance;
55 private U1MusicAPI mApi;64 private U1MusicAPI mApi;
5665
=== modified file 'src/com/ubuntuone/android/music/provider/MusicContentValues.java'
--- src/com/ubuntuone/android/music/provider/MusicContentValues.java 2012-11-13 13:58:31 +0000
+++ src/com/ubuntuone/android/music/provider/MusicContentValues.java 2012-11-21 17:34:22 +0000
@@ -25,6 +25,7 @@
2525
26import java.util.ArrayList;26import java.util.ArrayList;
27import java.util.Iterator;27import java.util.Iterator;
28import java.util.Locale;
28import java.util.Map.Entry;29import java.util.Map.Entry;
29import java.util.Random;30import java.util.Random;
30import java.util.Set;31import java.util.Set;
@@ -52,12 +53,16 @@
52 53
53 private static final boolean PRINT_CONTENT_VALUES = false;54 private static final boolean PRINT_CONTENT_VALUES = false;
54 55
55 public static ContentValues from(U1Artist artist) {56 public static String getAlbumList(U1Artist artist) {
57 return StringUtils.join(artist.getAlbumIds(), ",");
58 }
59
60 public static ContentValues forArtist(U1Artist artist) {
56 final ContentValues cv = new ContentValues();61 final ContentValues cv = new ContentValues();
57 cv.put(Artists.UPDATED, System.currentTimeMillis());62 cv.put(Artists.UPDATED, System.currentTimeMillis());
58 cv.put(Artists.ARTIST_ID, artist.getId());63 cv.put(Artists.ARTIST_ID, artist.getId());
59 cv.put(Artists.ARTIST_NAME, artist.getArtist());64 cv.put(Artists.ARTIST_NAME, artist.getArtist());
60 cv.put(Artists.ALBUM_LIST, StringUtils.join(artist.getAlbumIds(), ","));65 cv.put(Artists.ALBUM_LIST, getAlbumList(artist));
61 cv.put(Artists.ALBUM_COUNT, artist.getAlbumIds().size());66 cv.put(Artists.ALBUM_COUNT, artist.getAlbumIds().size());
62 cv.put(Artists.SONG_COUNT, artist.getSongCount());67 cv.put(Artists.SONG_COUNT, artist.getSongCount());
63 cv.put(Artists.ARTIST_URL, artist.getArtistUrl());68 cv.put(Artists.ARTIST_URL, artist.getArtistUrl());
@@ -66,7 +71,7 @@
66 return cv;71 return cv;
67 }72 }
68 73
69 public static ArrayList<ContentValues> albumsFrom(U1Artist artist) {74 public static ArrayList<ContentValues> forArtistAlbums(U1Artist artist) {
70 ArrayList<ContentValues> values = new ArrayList<ContentValues>();75 ArrayList<ContentValues> values = new ArrayList<ContentValues>();
71 ArrayList<String> albumIds = artist.getAlbumIds();76 ArrayList<String> albumIds = artist.getAlbumIds();
72 for (String albumId : albumIds) {77 for (String albumId : albumIds) {
@@ -80,13 +85,13 @@
80 return values;85 return values;
81 }86 }
8287
83 public static ContentValues from(U1Album album) {88 public static ContentValues forAlbum(U1Album album) {
84 final ContentValues cv = new ContentValues();89 final ContentValues cv = new ContentValues();
85 cv.put(Albums.UPDATED, System.currentTimeMillis());90 cv.put(Albums.UPDATED, System.currentTimeMillis());
86 cv.put(Albums.ALBUM_ID, album.getId());91 cv.put(Albums.ALBUM_ID, album.getId());
87 cv.put(Albums.ALBUM_TITLE, album.getTitle());92 cv.put(Albums.ALBUM_TITLE, album.getTitle());
88 cv.put(Albums.ALBUM_ARTIST, album.getArtist());93 cv.put(Albums.ALBUM_ARTIST, album.getArtist());
89 cv.put(Albums.ALBUM_ARTIST_ID, HashUtils.md5(album.getArtist()));94 cv.put(Albums.ALBUM_ARTIST_ID, album.getArtistId());
90 cv.put(Albums.ALBUM_YEAR, album.getYear());95 cv.put(Albums.ALBUM_YEAR, album.getYear());
91 cv.put(Albums.ALBUM_DATE_ADDED, album.getParsedDate());96 cv.put(Albums.ALBUM_DATE_ADDED, album.getParsedDate());
92 cv.put(Albums.ALBUM_URL, album.getAlbumUrl());97 cv.put(Albums.ALBUM_URL, album.getAlbumUrl());
@@ -95,7 +100,7 @@
95 return cv;100 return cv;
96 }101 }
97 102
98 public static ContentValues from(U1Song song) {103 public static ContentValues forSong(U1Song song) {
99 final ContentValues cv = new ContentValues();104 final ContentValues cv = new ContentValues();
100 cv.put(Songs.UPDATED, System.currentTimeMillis());105 cv.put(Songs.UPDATED, System.currentTimeMillis());
101 cv.put(Songs.SONG_ID, song.getId());106 cv.put(Songs.SONG_ID, song.getId());
@@ -104,10 +109,10 @@
104 cv.put(Songs.SONG_ALBUM_ID, song.getAlbumId());109 cv.put(Songs.SONG_ALBUM_ID, song.getAlbumId());
105 cv.put(Songs.SONG_ALBUM_ARTIST, song.getAlbumArtist());110 cv.put(Songs.SONG_ALBUM_ARTIST, song.getAlbumArtist());
106 cv.put(Songs.SONG_ARTIST, song.getArtist());111 cv.put(Songs.SONG_ARTIST, song.getArtist());
107 cv.put(Songs.SONG_ARTIST_ID, HashUtils.md5(song.getArtist()));112 cv.put(Songs.SONG_ARTIST_ID, song.getArtistId());
108 cv.put(Songs.SONG_GENRE, song.getGenre());113 cv.put(Songs.SONG_GENRE, song.getGenre());
109 // TODO Calculate /0 separated genre md5 sums maybe?114 // TODO Calculate /0 separated genre md5 sums maybe?
110 cv.put(Songs.SONG_GENRE_ID, HashUtils.md5(song.getGenre().toUpperCase()));115 cv.put(Songs.SONG_GENRE_ID, getGenreId(song.getGenre()));
111 cv.put(Songs.SONG_YEAR, song.getYear());116 cv.put(Songs.SONG_YEAR, song.getYear());
112 cv.put(Songs.SONG_DISC_NUMBER, song.getDiscNumber());117 cv.put(Songs.SONG_DISC_NUMBER, song.getDiscNumber());
113 cv.put(Songs.SONG_TRACK, song.getTrack());118 cv.put(Songs.SONG_TRACK, song.getTrack());
@@ -125,7 +130,7 @@
125 return cv;130 return cv;
126 }131 }
127 132
128 public static ContentValues from(U1Playlist playlist) {133 public static ContentValues forPlaylist(U1Playlist playlist) {
129 final ContentValues cv = new ContentValues();134 final ContentValues cv = new ContentValues();
130 cv.put(Playlists.UPDATED, System.currentTimeMillis());135 cv.put(Playlists.UPDATED, System.currentTimeMillis());
131 cv.put(Playlists.PLAYLIST_ID, playlist.getId());136 cv.put(Playlists.PLAYLIST_ID, playlist.getId());
@@ -136,7 +141,7 @@
136 return cv;141 return cv;
137 }142 }
138 143
139 public static ContentValues from(String playlistId, String songId) {144 public static ContentValues forPlaylistSong(String playlistId, String songId) {
140 final ContentValues cv = new ContentValues();145 final ContentValues cv = new ContentValues();
141 cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis());146 cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis());
142 cv.put(PlaylistSongs.PLAYLIST_ID, playlistId);147 cv.put(PlaylistSongs.PLAYLIST_ID, playlistId);
@@ -145,7 +150,7 @@
145 return cv;150 return cv;
146 }151 }
147 152
148 public static ContentValues from(Random random) {153 public static ContentValues forShuffleOrder(Random random) {
149 final ContentValues cv = new ContentValues();154 final ContentValues cv = new ContentValues();
150 cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis());155 cv.put(PlaylistSongs.UPDATED, System.currentTimeMillis());
151 cv.put(PlaylistSongs.SHUFFLE_ORDER, random.nextLong());156 cv.put(PlaylistSongs.SHUFFLE_ORDER, random.nextLong());
@@ -153,10 +158,14 @@
153 return cv;158 return cv;
154 }159 }
155 160
156 public static ContentValues fromGenre(String genre) {161 public static String getGenreId(String genre) {
162 return HashUtils.md5(genre.toLowerCase(Locale.US));
163 }
164
165 public static ContentValues forGenre(String genre) {
157 final ContentValues cv = new ContentValues();166 final ContentValues cv = new ContentValues();
158 cv.put(Genres.UPDATED, System.currentTimeMillis());167 cv.put(Genres.UPDATED, System.currentTimeMillis());
159 cv.put(Genres.GENRE_ID, HashUtils.md5(genre.toUpperCase()));168 cv.put(Genres.GENRE_ID, getGenreId(genre));
160 cv.put(Genres.GENRE_TITLE, genre);169 cv.put(Genres.GENRE_TITLE, genre);
161 return cv;170 return cv;
162 }171 }
163172
=== modified file 'src/com/ubuntuone/android/music/provider/MusicContract.java'
--- src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-08 14:14:54 +0000
+++ src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-21 17:34:22 +0000
@@ -273,7 +273,7 @@
273 }273 }
274 }274 }
275 275
276 /* package */ static class ArtistAlbums implements ArtistAlbumsColumns, SyncColumns,276 public static class ArtistAlbums implements ArtistAlbumsColumns, SyncColumns,
277 SongsColumns, BaseColumns277 SongsColumns, BaseColumns
278 {278 {
279 public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()279 public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
280280
=== modified file 'src/com/ubuntuone/android/music/provider/MusicDatabase.java'
--- src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-13 13:58:31 +0000
+++ src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-21 17:34:22 +0000
@@ -61,7 +61,7 @@
61 61
62 //private static final String NOW = "strftime('%s', 'now')";62 //private static final String NOW = "strftime('%s', 'now')";
6363
64 interface Tables64 public interface Tables
65 {65 {
66 String ARTISTS = "artists";66 String ARTISTS = "artists";
67 String ARTISTS_ALBUMS = "artists_albums";67 String ARTISTS_ALBUMS = "artists_albums";
@@ -115,7 +115,7 @@
115 @Override115 @Override
116 public SQLiteDatabase getWritableDatabase() {116 public SQLiteDatabase getWritableDatabase() {
117 SQLiteDatabase db = super.getWritableDatabase();117 SQLiteDatabase db = super.getWritableDatabase();
118 if (UbuntuOneMusic.DEBUG_SHOULD_USE_FK) {118 if (UbuntuOneMusic.SHOULD_USE_FK) {
119 db.execSQL("PRAGMA foreign_keys = ON");119 db.execSQL("PRAGMA foreign_keys = ON");
120 }120 }
121 return db;121 return db;
@@ -207,7 +207,7 @@
207 // Create the play queue playlist.207 // Create the play queue playlist.
208 U1Playlist queuePlaylist = new U1Playlist(208 U1Playlist queuePlaylist = new U1Playlist(
209 MusicProviderUtils.QUEUE_ID, "", MusicProviderUtils.QUEUE_NAME, 0);209 MusicProviderUtils.QUEUE_ID, "", MusicProviderUtils.QUEUE_NAME, 0);
210 ContentValues values = MusicContentValues.from(queuePlaylist);210 ContentValues values = MusicContentValues.forPlaylist(queuePlaylist);
211 db.insert(Tables.PLAYLISTS, null, values);211 db.insert(Tables.PLAYLISTS, null, values);
212 212
213 db.execSQL("CREATE TABLE " + Tables.PLAYLISTS_SONGS + "("213 db.execSQL("CREATE TABLE " + Tables.PLAYLISTS_SONGS + "("
214214
=== modified file 'src/com/ubuntuone/android/music/provider/MusicProvider.java'
--- src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-08 14:14:54 +0000
+++ src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-21 17:34:22 +0000
@@ -325,7 +325,7 @@
325 String lcGenre = genre != null ? genre.trim().toLowerCase() : "";325 String lcGenre = genre != null ? genre.trim().toLowerCase() : "";
326 if (!TextUtils.isEmpty(lcGenre) && !lcGenre.equals("null") && !lcGenre.equals("genre")) {326 if (!TextUtils.isEmpty(lcGenre) && !lcGenre.equals("null") && !lcGenre.equals("genre")) {
327 // XXX Do we want all genres uppercase? If so, toUpperCase() genre below.327 // XXX Do we want all genres uppercase? If so, toUpperCase() genre below.
328 ContentValues genreValues = MusicContentValues.fromGenre(genre.trim());328 ContentValues genreValues = MusicContentValues.forGenre(genre.trim());
329 db.insertOrThrow(Tables.GENRES, null, genreValues);329 db.insertOrThrow(Tables.GENRES, null, genreValues);
330 }330 }
331 }331 }
332332
=== modified file 'src/com/ubuntuone/android/music/provider/MusicProviderUtils.java'
--- src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-08 14:14:54 +0000
+++ src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-21 17:34:22 +0000
@@ -242,7 +242,7 @@
242 String playlistId = Playlists.getPlaylistId(playlistUri);242 String playlistId = Playlists.getPlaylistId(playlistUri);
243 String songId = Songs.getSongId(songUri);243 String songId = Songs.getSongId(songUri);
244 244
245 ContentValues values = MusicContentValues.from(playlistId, songId);245 ContentValues values = MusicContentValues.forPlaylistSong(playlistId, songId);
246 resolver.insert(playlistUri, values);246 resolver.insert(playlistUri, values);
247 }247 }
248 248
@@ -261,7 +261,7 @@
261 if (cursor != null && cursor.isBeforeFirst()) {261 if (cursor != null && cursor.isBeforeFirst()) {
262 while (cursor.moveToNext()) {262 while (cursor.moveToNext()) {
263 String songId = cursor.getString(cursor.getColumnIndex(Songs.SONG_ID));263 String songId = cursor.getString(cursor.getColumnIndex(Songs.SONG_ID));
264 ContentValues values = MusicContentValues.from(264 ContentValues values = MusicContentValues.forPlaylistSong(
265 MusicProviderUtils.QUEUE_ID, songId);265 MusicProviderUtils.QUEUE_ID, songId);
266 resolver.insert(MusicProviderUtils.QUEUE_URI, values);266 resolver.insert(MusicProviderUtils.QUEUE_URI, values);
267 }267 }
@@ -650,7 +650,7 @@
650 String playlistId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.PLAYLIST_ID));650 String playlistId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.PLAYLIST_ID));
651 String songId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.SONG_ID));651 String songId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.SONG_ID));
652 Uri queueSongUri = Playlists.buildPlaylistSongUri(playlistId, songId);652 Uri queueSongUri = Playlists.buildPlaylistSongUri(playlistId, songId);
653 ContentValues values = MusicContentValues.from(random);653 ContentValues values = MusicContentValues.forShuffleOrder(random);
654 654
655 resolver.update(queueSongUri, values, null, null);655 resolver.update(queueSongUri, values, null, null);
656 }656 }
657657
=== added directory 'src/com/ubuntuone/android/music/provider/dao'
=== added file 'src/com/ubuntuone/android/music/provider/dao/AlbumDao.java'
--- src/com/ubuntuone/android/music/provider/dao/AlbumDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/AlbumDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,130 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import android.content.ContentResolver;
4import android.content.ContentValues;
5import android.database.sqlite.SQLiteDatabase;
6import android.database.sqlite.SQLiteStatement;
7import android.net.Uri;
8
9import com.ubuntuone.android.music.provider.MusicContentValues;
10import com.ubuntuone.android.music.provider.MusicContract.Albums;
11import com.ubuntuone.android.music.provider.MusicDatabase;
12import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
13import com.ubuntuone.android.music.provider.MusicProvider;
14import com.ubuntuone.api.music.model.U1Album;
15
16public class AlbumDao extends Dao
17{
18 public AlbumDao() {
19 }
20
21 /**
22 * Updates the album. If the album doesn't exist, inserts the album.
23 * Backed by {@link MusicProvider}.
24 *
25 * @param resolver
26 * The content resolver.
27 * @param artist
28 * The {@link U1Album} to save.
29 */
30 public void updateOrInsert(ContentResolver resolver, U1Album album) {
31 ContentValues values = MusicContentValues.forAlbum(album);
32 Uri albumUri = Albums.buildAlbumUri(album.getId());
33 int count = resolver.update(albumUri, values, null, null);
34 if (count == 0) {
35 resolver.insert(Albums.CONTENT_URI, values);
36 }
37 }
38
39 /**
40 * Updates the album. If the album doesn't exist, inserts the album.
41 * Backed by {@link MusicDatabase}.
42 *
43 * @param db
44 * The {@link MusicDatabase} instance.
45 * @param artist
46 * The {@link U1Album} to save.
47 * @return True if update or insert succeeded, false otherwise.
48 */
49 public boolean updateOrInsert(SQLiteDatabase db, U1Album album) {
50 boolean isSuccess = false;
51
52 SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql());
53 int i = 1; // Index to the parameter to bind.
54 sqlStmt.bindLong(i++, System.currentTimeMillis());
55
56 sqlStmt.bindString(i++, album.getTitle());
57 sqlStmt.bindString(i++, album.getArtist());
58 sqlStmt.bindString(i++, album.getArtistId());
59 sqlStmt.bindLong(i++, album.getYear());
60
61 sqlStmt.bindLong(i++, album.getParsedDate());
62 sqlStmt.bindString(i++, album.getAlbumUrl());
63 sqlStmt.bindString(i++, album.getAlbumArtUrl());
64
65 sqlStmt.bindString(i++, album.getId());
66 // Can't use executeUpdateDelete on API < 11
67 sqlStmt.execute();
68 long rowsUpdated = getChanges(db);
69
70 if (rowsUpdated == 0L) {
71 sqlStmt = db.compileStatement(getInsertSql());
72 i = 1;
73 sqlStmt.bindLong(i++, System.currentTimeMillis());
74 sqlStmt.bindString(i++, album.getId());
75
76 sqlStmt.bindString(i++, album.getTitle());
77 sqlStmt.bindString(i++, album.getArtist());
78 sqlStmt.bindString(i++, album.getArtistId());
79 sqlStmt.bindLong(i++, album.getYear());
80
81 sqlStmt.bindLong(i++, album.getParsedDate());
82 sqlStmt.bindString(i++, album.getAlbumUrl());
83 sqlStmt.bindString(i++, album.getAlbumArtUrl());
84
85 long rowId = sqlStmt.executeInsert();
86 isSuccess = rowId != -1;
87 } else {
88 isSuccess = rowsUpdated == 1;
89 }
90 return isSuccess;
91 }
92
93 @Override
94 public String onGetInsertSql() {
95 return "INSERT INTO " + Tables.ALBUMS + "(" +
96 Albums.UPDATED + ", " +
97 Albums.ALBUM_ID + ", " +
98
99 Albums.ALBUM_TITLE + ", " +
100 Albums.ALBUM_ARTIST + ", " +
101 Albums.ALBUM_ARTIST_ID + ", " +
102 Albums.ALBUM_YEAR + ", " +
103
104 Albums.ALBUM_DATE_ADDED + ", " +
105 Albums.ALBUM_URL + ", " +
106 Albums.ALBUM_ART_URL +
107
108 ") VALUES (?, ?, " +
109 "?, ?, ?, ?, " +
110 "?, ?, ?" +
111 ")";
112 }
113
114 @Override
115 public String onGetUpdateSql() {
116 return "UPDATE " + Tables.ALBUMS + " SET " +
117 Albums.UPDATED + "=?, " +
118
119 Albums.ALBUM_TITLE + "=?, " +
120 Albums.ALBUM_ARTIST + "=?, " +
121 Albums.ALBUM_ARTIST_ID + "=?, " +
122 Albums.ALBUM_YEAR + "=?, " +
123
124 Albums.ALBUM_DATE_ADDED + "=?, " +
125 Albums.ALBUM_URL + "=?, " +
126 Albums.ALBUM_ART_URL + "=? " +
127
128 "WHERE " + Albums.ALBUM_ID + "=?";
129 }
130}
0131
=== added file 'src/com/ubuntuone/android/music/provider/dao/ArtistDao.java'
--- src/com/ubuntuone/android/music/provider/dao/ArtistDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/ArtistDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,170 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import java.util.ArrayList;
4
5import android.content.ContentResolver;
6import android.content.ContentValues;
7import android.database.sqlite.SQLiteDatabase;
8import android.database.sqlite.SQLiteStatement;
9import android.net.Uri;
10
11import com.ubuntuone.android.music.provider.MusicContentValues;
12import com.ubuntuone.android.music.provider.MusicContract.Albums;
13import com.ubuntuone.android.music.provider.MusicContract.ArtistAlbums;
14import com.ubuntuone.android.music.provider.MusicContract.Artists;
15import com.ubuntuone.android.music.provider.MusicDatabase;
16import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
17import com.ubuntuone.android.music.provider.MusicProvider;
18import com.ubuntuone.android.music.util.StringUtils;
19import com.ubuntuone.api.music.model.U1Artist;
20
21public class ArtistDao extends Dao
22{
23 public ArtistDao() {
24 }
25
26 /**
27 * Updates the artist. If the artist doesn't exist, inserts the artist.
28 * Backed by {@link MusicProvider}.
29 *
30 * @param resolver
31 * The content resolver.
32 * @param artist
33 * The {@link U1Artist} to save.
34 */
35 public void updateOrInsert(ContentResolver resolver, U1Artist artist) {
36 ContentValues values = MusicContentValues.forArtist(artist);
37 Uri artistUri = Artists.buildArtistUri(artist.getId());
38 int count = resolver.update(artistUri, values, null, null);
39 if (count == 0) {
40 resolver.insert(Artists.CONTENT_URI, values);
41 }
42 // Insert artist albums.
43 ArrayList<ContentValues> albumsValues = MusicContentValues.forArtistAlbums(artist);
44 for (ContentValues albumValues : albumsValues) {
45 Uri artistAlbumUri = Artists.buildAlbumUri(
46 artist.getId(), albumValues.getAsString(Albums.ALBUM_ID));
47 int count2 = resolver.update(artistAlbumUri, albumValues, null, null);
48 if (count2 == 0) {
49 resolver.insert(artistAlbumUri, albumValues);
50 }
51 }
52 }
53
54 /**
55 * Updates the artist. If the artist doesn't exist, inserts the artist.
56 * Backed by {@link MusicDatabase}.
57 *
58 * @param db
59 * The {@link MusicDatabase} instance.
60 * @param artist
61 * The {@link U1Artist} to save.
62 * @return True if update or insert succeeded, false otherwise.
63 */
64 public boolean updateOrInsert(SQLiteDatabase db, U1Artist artist) {
65 boolean isSuccess = false;
66
67 SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql());
68 int i = 1; // Index to the parameter to bind.
69
70 final String albumList = StringUtils.join(artist.getAlbumIds(), ",");
71 final long albumListSize = artist.getAlbumIds().size();
72
73 sqlStmt.bindLong(i++, System.currentTimeMillis());
74
75 sqlStmt.bindString(i++, artist.getArtist());
76 sqlStmt.bindString(i++, albumList);
77 sqlStmt.bindLong(i++, albumListSize);
78 sqlStmt.bindLong(i++, artist.getSongCount());
79
80 sqlStmt.bindString(i++, artist.getArtistUrl());
81 sqlStmt.bindString(i++, artist.getArtistArtUrl());
82
83 sqlStmt.bindString(i++, artist.getId());
84 // Can't use executeUpdateDelete on API < 11
85 sqlStmt.execute();
86 long rowsUpdated = getChanges(db);
87
88 if (rowsUpdated == 0L) {
89 sqlStmt = db.compileStatement(getInsertSql());
90 i = 1;
91 sqlStmt.bindLong(i++, System.currentTimeMillis());
92 sqlStmt.bindString(i++, artist.getId());
93
94 sqlStmt.bindString(i++, artist.getArtist());
95 sqlStmt.bindString(i++, albumList);
96 sqlStmt.bindLong(i++, albumListSize);
97 sqlStmt.bindLong(i++, artist.getSongCount());
98
99 sqlStmt.bindString(i++, artist.getArtistUrl());
100 sqlStmt.bindString(i++, artist.getArtistArtUrl());
101
102 long rowId = sqlStmt.executeInsert();
103 isSuccess = rowId != -1;
104 } else {
105 isSuccess = rowsUpdated == 1;
106 }
107
108 // Insert artist albums.
109 sqlStmt = db.compileStatement(getSecondaryInsertSql());
110 final String artistId = artist.getId();
111 final ArrayList<String> albumIds = artist.getAlbumIds();
112 for (String albumId : albumIds) {
113 sqlStmt.clearBindings();
114 sqlStmt.bindLong(1, System.currentTimeMillis());
115 sqlStmt.bindString(2, artistId);
116 sqlStmt.bindString(3, albumId);
117 long rowId = sqlStmt.executeInsert();
118 isSuccess = isSuccess && (rowId != -1);
119 }
120
121 return isSuccess;
122 }
123
124 @Override
125 public String onGetInsertSql() {
126 return "INSERT INTO " + Tables.ARTISTS + "(" +
127 Artists.UPDATED + ", " +
128 Artists.ARTIST_ID + ", " +
129
130 Artists.ARTIST_NAME + ", " +
131 Artists.ALBUM_LIST + ", " +
132 Artists.ALBUM_COUNT + ", " +
133 Artists.SONG_COUNT + ", " +
134
135 Artists.ARTIST_URL + ", " +
136 Artists.ARTIST_ART_URL +
137
138 ") VALUES (?, ?, " +
139 "?, ?, ?, ?, " +
140 "?, ?" +
141 ")";
142 }
143
144 @Override
145 public String onGetSecondaryInsertSql() {
146 return "INSERT INTO " + Tables.ARTISTS_ALBUMS + "(" +
147
148 ArtistAlbums.UPDATED + ", " +
149 ArtistAlbums.ARTIST_ID + ", " +
150 ArtistAlbums.ALBUM_ID +
151
152 ") VALUES (?, ?, ?)";
153 }
154
155 @Override
156 public String onGetUpdateSql() {
157 return "UPDATE " + Tables.ARTISTS + " SET " +
158 Artists.UPDATED + "=?, " +
159
160 Artists.ARTIST_NAME + "=?, " +
161 Artists.ALBUM_LIST + "=?, " +
162 Artists.ALBUM_COUNT + "=?, " +
163 Artists.SONG_COUNT + "=?, " +
164
165 Artists.ARTIST_URL + "=?, " +
166 Artists.ARTIST_ART_URL + "=? " +
167
168 "WHERE " + Artists.ARTIST_ID + "=?";
169 }
170}
0171
=== added file 'src/com/ubuntuone/android/music/provider/dao/Dao.java'
--- src/com/ubuntuone/android/music/provider/dao/Dao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/Dao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,76 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import android.database.sqlite.SQLiteDatabase;
4import android.database.sqlite.SQLiteStatement;
5
6public abstract class Dao
7{
8 private String mInsertSql;
9 private String mSecondaryInsertSql;
10 private String mUdpateSql;
11
12 /**
13 * Performs a lazy initialization with {@code Dao#onGetInsertSql()}.
14 *
15 * @return The cached SQL INSERT string.
16 */
17 public String getInsertSql() {
18 if (mInsertSql == null) {
19 mInsertSql = onGetInsertSql();
20 }
21 return mInsertSql;
22 }
23
24 /**
25 * Performs a lazy initialization with {@code Dao#onGetSecondaryInsertSql()}.
26 *
27 * @return The cached secondary SQL INSERT string.
28 */
29 public String getSecondaryInsertSql() {
30 if (mSecondaryInsertSql == null) {
31 mSecondaryInsertSql = onGetSecondaryInsertSql();
32 }
33 return mSecondaryInsertSql;
34 }
35
36 /**
37 * Performs a lazy initialization with {@code Dao#onGetUpdateSql()}.
38 *
39 * @return The cached SQL UPDATE string.
40 */
41 public String getUpdateSql() {
42 if (mUdpateSql == null) {
43 mUdpateSql = onGetUpdateSql();
44 }
45 return mUdpateSql;
46 }
47
48 public long getChanges(SQLiteDatabase db) {
49 SQLiteStatement countStmt = db.compileStatement("SELECT changes()");
50 return countStmt.simpleQueryForLong();
51 }
52
53 /**
54 * Override to return the SQL INSERT string.
55 *
56 * @return The SQL INSERT string.
57 */
58 public abstract String onGetInsertSql();
59
60
61 /**
62 * Override to return the secondary SQL INSERT string.
63 *
64 * @return The secondary SQL INSERT string.
65 */
66 public String onGetSecondaryInsertSql() {
67 return null;
68 }
69
70 /**
71 * Override to return the SQL UPDATE string.
72 *
73 * @return The SQL UPDATE string.
74 */
75 public abstract String onGetUpdateSql();
76}
077
=== added file 'src/com/ubuntuone/android/music/provider/dao/GenreDao.java'
--- src/com/ubuntuone/android/music/provider/dao/GenreDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/GenreDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,86 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import android.content.ContentResolver;
4import android.content.ContentValues;
5import android.database.sqlite.SQLiteDatabase;
6import android.database.sqlite.SQLiteStatement;
7import android.text.TextUtils;
8
9import com.ubuntuone.android.music.provider.MusicContentValues;
10import com.ubuntuone.android.music.provider.MusicContract.Genres;
11import com.ubuntuone.android.music.provider.MusicDatabase;
12import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
13import com.ubuntuone.android.music.provider.MusicProvider;
14import com.ubuntuone.android.music.util.HashUtils;
15import com.ubuntuone.api.music.model.U1Song;
16
17public class GenreDao extends Dao
18{
19 public GenreDao() {
20 }
21
22 /**
23 * Inserts song genre. Backed by {@link MusicProvider}.
24 *
25 * @param resolver
26 * The content resolver.
27 * @param song
28 * The {@link U1Song} of which genre to save.
29 */
30 public void updateOrInsert(ContentResolver resolver, U1Song song) {
31 String genre = song.getGenre();
32 String lcGenre = genre != null ? genre.trim().toLowerCase() : null;
33 if (!TextUtils.isEmpty(lcGenre) &&
34 !lcGenre.equals("null") && !lcGenre.equals("genre")) {
35 // XXX Do we want all genres uppercase? If so, toUpperCase() genre below.
36 ContentValues genreValues = MusicContentValues.forGenre(genre.trim());
37 resolver.insert(Genres.CONTENT_URI, genreValues);
38 }
39 }
40
41 /**
42 * Inserts song genre. Backed by {@link MusicDatabase}.
43 *
44 * @param db
45 * The {@link MusicDatabase} instance.
46 * @param song
47 * The {@link U1Song} of which genre to save.
48 * @return Always true for genre.
49 */
50 public boolean updateOrInsert(SQLiteDatabase db, String genre) {
51 final SQLiteStatement genreInsert = db.compileStatement(getInsertSql());
52 genreInsert.clearBindings();
53
54 String lcGenre = genre != null ? genre.trim().toLowerCase() : null;
55 if (TextUtils.isEmpty(lcGenre) ||
56 lcGenre.equals("null") || lcGenre.equals("genre")) {
57 // Ignore generic crap. Assume genre was inserted, we don't care.
58 return true;
59 }
60 String genreId = HashUtils.md5(genre.toUpperCase());
61
62 int j = 1; // Index to the parameter to bind.
63 genreInsert.bindLong(j++, System.currentTimeMillis());
64 genreInsert.bindString(j++, genreId);
65 genreInsert.bindString(j++, genre);
66
67 genreInsert.executeInsert();
68 // Assume genre was inserted, we don't care.
69 return true;
70 }
71
72 @Override
73 public String onGetInsertSql() {
74 return "INSERT INTO " + Tables.GENRES + "(" +
75 Genres.UPDATED + ", " +
76 Genres.GENRE_ID + ", " +
77 Genres.GENRE_TITLE +
78 ") VALUES (?, ?, ?)";
79 }
80
81 @Override
82 public String onGetUpdateSql() {
83 // Not used for genre.
84 return null;
85 }
86}
087
=== added file 'src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java'
--- src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/PlaylistDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,109 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import android.content.ContentResolver;
4import android.content.ContentValues;
5import android.database.sqlite.SQLiteDatabase;
6import android.database.sqlite.SQLiteStatement;
7import android.net.Uri;
8
9import com.ubuntuone.android.music.provider.MusicContentValues;
10import com.ubuntuone.android.music.provider.MusicContract.Playlists;
11import com.ubuntuone.android.music.provider.MusicDatabase;
12import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
13import com.ubuntuone.android.music.provider.MusicProvider;
14import com.ubuntuone.api.music.model.U1Playlist;
15
16public class PlaylistDao extends Dao
17{
18 public PlaylistDao() {
19 }
20
21 /**
22 * Updates the playlist. If the playlist doesn't exist, inserts the playlist.
23 * Backed by {@link MusicProvider}.
24 *
25 * @param resolver
26 * The content resolver.
27 * @param playlist
28 * The {@link U1Playlist} to save.
29 */
30 public void updateOrInsert(ContentResolver resolver, U1Playlist playlist) {
31 ContentValues values = MusicContentValues.forPlaylist(playlist);
32 Uri playlistUri = Playlists.buildPlaylistUri(playlist.getId());
33 int count = resolver.update(playlistUri, values, null, null);
34 if (count == 0) {
35 resolver.insert(Playlists.CONTENT_URI, values);
36 }
37 }
38
39 /**
40 * Updates the playlist. If the playlist doesn't exist, inserts the playlist.
41 * Backed by {@link MusicDatabase}.
42 *
43 * @param db
44 * The {@link MusicDatabase} instance.
45 * @param playlist
46 * The {@link U1Playlist} to save.
47 * @return True if update or insert succeeded, false otherwise.
48 */
49 public boolean updateOrInsert(SQLiteDatabase db, U1Playlist playlist) {
50 boolean isSuccess = false;
51
52 SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql());
53 int i = 1; // Index to the parameter to bind.
54
55 sqlStmt.bindLong(i++, System.currentTimeMillis());
56
57 sqlStmt.bindString(i++, playlist.getName());
58 sqlStmt.bindLong(i++, playlist.getSongCount());
59 sqlStmt.bindString(i++, playlist.getPlaylistUrl());
60
61 sqlStmt.bindString(i++, playlist.getId());
62 // Can't use executeUpdateDelete on API < 11
63 sqlStmt.execute();
64 long rowsUpdated = getChanges(db);
65
66 if (rowsUpdated == 0L) {
67 sqlStmt = db.compileStatement(getInsertSql());
68 i = 1;
69 sqlStmt.bindLong(i++, System.currentTimeMillis());
70
71 sqlStmt.bindString(i++, playlist.getId());
72 sqlStmt.bindString(i++, playlist.getName());
73 sqlStmt.bindLong(i++, playlist.getSongCount());
74 sqlStmt.bindString(i++, playlist.getPlaylistUrl());
75
76 long rowId = sqlStmt.executeInsert();
77 isSuccess = rowId != -1;
78 } else {
79 isSuccess = rowsUpdated == 1;
80 }
81 return isSuccess;
82 }
83
84 @Override
85 public String onGetInsertSql() {
86 return "INSERT INTO " + Tables.PLAYLISTS + "(" +
87 Playlists.UPDATED + ", " +
88 Playlists.PLAYLIST_ID + ", " +
89
90 Playlists.PLAYLIST_NAME + ", " +
91 Playlists.PLAYLIST_SONG_COUNT + ", " +
92 Playlists.PLAYLIST_URL +
93
94 ") VALUES (?, ?, " +
95 "?, ?, ?" +
96 ")";
97 }
98
99 @Override
100 public String onGetUpdateSql() {
101 return "UPDATE " + Tables.PLAYLISTS + " SET " +
102 Playlists.UPDATED + "=?, " +
103 Playlists.PLAYLIST_NAME + "=?, " +
104 Playlists.PLAYLIST_SONG_COUNT + "=?, " +
105 Playlists.PLAYLIST_URL + "=? " +
106 "WHERE " + Playlists.PLAYLIST_ID + "=?";
107
108 }
109}
0110
=== added file 'src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java'
--- src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/PlaylistSongDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,97 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import android.content.ContentResolver;
4import android.content.ContentValues;
5import android.database.sqlite.SQLiteDatabase;
6import android.database.sqlite.SQLiteStatement;
7import android.net.Uri;
8
9import com.ubuntuone.android.music.provider.MusicContentValues;
10import com.ubuntuone.android.music.provider.MusicContract.PlaylistSongs;
11import com.ubuntuone.android.music.provider.MusicContract.Playlists;
12import com.ubuntuone.android.music.provider.MusicContract.Songs;
13import com.ubuntuone.android.music.provider.MusicDatabase;
14import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
15import com.ubuntuone.android.music.provider.MusicProvider;
16import com.ubuntuone.api.music.model.U1Song;
17
18public class PlaylistSongDao extends Dao
19{
20 public PlaylistSongDao() {
21 }
22
23 /**
24 * Updates the playlist song. If the playlist song doesn't exist, inserts
25 * the playlist song. Backed by {@link MusicProvider}.
26 *
27 * @param resolver
28 * The content resolver.
29 * @param playlistId
30 * The playlist id of the playlist to save the song to.
31 * @param song
32 * The {@link U1Song} to save.
33 */
34 public void updateOrInsert(ContentResolver resolver, String playlistId, U1Song song) {
35 ContentValues values = MusicContentValues.forPlaylistSong(playlistId, song.getId());
36 Uri playlistSongsUri = Playlists.buildPlaylistSongUri(playlistId, song.getId());
37 int count = resolver.update(playlistSongsUri, values, null, null);
38 if (count == 0) {
39 resolver.insert(playlistSongsUri, values);
40 }
41 }
42
43 /**
44 * Updates the playlist song. If the playlist song doesn't exist, inserts
45 * the playlist song. Backed by {@link MusicDatabase}.
46 *
47 * @param db
48 * The {@link MusicDatabase} instance.
49 * @param playlistId
50 * The playlist id of the playlist to save the song to.
51 * @param song
52 * The {@link U1Song} to save.
53 * @return True if update or insert succeeded, false otherwise.
54 */
55 public boolean updateOrInsert(SQLiteDatabase db, String playlistId, String songId) {
56 boolean isSuccess = false;
57
58 SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql());
59 int i = 1; // Index to the parameter to bind.
60 sqlStmt.bindLong(i++, System.currentTimeMillis());
61 sqlStmt.bindString(i++, playlistId);
62 sqlStmt.bindString(i++, songId);
63 // Can't use executeUpdateDelete on API < 11
64 sqlStmt.execute();
65 long rowsUpdated = getChanges(db);
66
67 if (rowsUpdated == 0L) {
68 sqlStmt = db.compileStatement(getInsertSql());
69 i = 1;
70 sqlStmt.bindLong(i++, System.currentTimeMillis());
71 sqlStmt.bindString(i++, playlistId);
72 sqlStmt.bindString(i++, songId);
73
74 long rowId = sqlStmt.executeInsert();
75 isSuccess = rowId != -1;
76 } else {
77 isSuccess = rowsUpdated == 1;
78 }
79 return isSuccess;
80 }
81
82 @Override
83 public String onGetInsertSql() {
84 return "INSERT INTO " + Tables.PLAYLISTS_SONGS + "(" +
85 PlaylistSongs.UPDATED + ", " +
86 PlaylistSongs.PLAYLIST_ID + ", " +
87 PlaylistSongs.SONG_ID +
88 ") VALUES (?, ?, ?)";
89 }
90
91 @Override
92 public String onGetUpdateSql() {
93 return "UPDATE " + Tables.PLAYLISTS_SONGS + " SET " +
94 PlaylistSongs.UPDATED + "=? " +
95 "WHERE " + PlaylistSongs.PLAYLIST_ID + "=? AND " + Songs.SONG_ID + "=?";
96 }
97}
098
=== added file 'src/com/ubuntuone/android/music/provider/dao/SongDao.java'
--- src/com/ubuntuone/android/music/provider/dao/SongDao.java 1970-01-01 00:00:00 +0000
+++ src/com/ubuntuone/android/music/provider/dao/SongDao.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,194 @@
1package com.ubuntuone.android.music.provider.dao;
2
3import static com.ubuntuone.android.music.provider.MusicContentValues.getGenreId;
4import android.content.ContentResolver;
5import android.content.ContentValues;
6import android.database.sqlite.SQLiteDatabase;
7import android.database.sqlite.SQLiteStatement;
8import android.net.Uri;
9
10import com.ubuntuone.android.music.provider.MusicContentValues;
11import com.ubuntuone.android.music.provider.MusicContract.Songs;
12import com.ubuntuone.android.music.provider.MusicDatabase;
13import com.ubuntuone.android.music.provider.MusicDatabase.Tables;
14import com.ubuntuone.android.music.provider.MusicProvider;
15import com.ubuntuone.api.music.model.U1Song;
16
17public class SongDao extends Dao
18{
19 public SongDao() {
20 }
21
22 /**
23 * Updates the song. If the song doesn't exist, inserts the song. Backed by
24 * {@link MusicProvider}.
25 *
26 * @param resolver
27 * The content resolver.
28 * @param song
29 * The {@link U1Song} to save.
30 */
31 public void updateOrInsert(ContentResolver resolver, U1Song song) {
32 ContentValues values = MusicContentValues.forSong(song);
33 Uri songUri = Songs.buildSongUri(song.getId());
34 int rowsUpdated = resolver.update(songUri, values, null, null);
35 if (rowsUpdated == 0) {
36 resolver.insert(Songs.CONTENT_URI, values);
37 }
38 }
39
40 /**
41 * Updates the song. If the song doesn't exist, inserts the song. Backed by
42 * {@link MusicDatabase}.
43 *
44 * @param db
45 * The {@link MusicDatabase} instance.
46 * @param song
47 * The {@link U1Song} to save.
48 * @return True if update or insert succeeded, false otherwise.
49 */
50 public boolean updateOrInsert(SQLiteDatabase db, U1Song song) {
51 boolean isSuccess = false;
52
53 SQLiteStatement sqlStmt = db.compileStatement(getUpdateSql());
54 int i = 1; // Index to the parameter to bind.
55 sqlStmt.bindLong(i++, System.currentTimeMillis());
56
57 sqlStmt.bindString(i++, song.getTitle());
58 sqlStmt.bindString(i++, song.getAlbum());
59 sqlStmt.bindString(i++, song.getAlbumId());
60 sqlStmt.bindString(i++, song.getAlbumArtist());
61
62 sqlStmt.bindString(i++, song.getArtist());
63 sqlStmt.bindString(i++, song.getArtistId());
64 sqlStmt.bindString(i++, song.getGenre());
65 sqlStmt.bindString(i++, getGenreId(song.getGenre()));
66
67 sqlStmt.bindLong(i++, song.getYear());
68 sqlStmt.bindLong(i++, song.getDiscNumber());
69 sqlStmt.bindLong(i++, song.getTrack());
70 sqlStmt.bindLong(i++, song.getDuration());
71
72 sqlStmt.bindLong(i++, song.getSize());
73 sqlStmt.bindLong(i++, song.getBitRate());
74 sqlStmt.bindString(i++, song.getSuffix());
75 sqlStmt.bindString(i++, song.getContentType());
76
77 sqlStmt.bindString(i++, song.getSongUrl());
78 sqlStmt.bindString(i++, song.getSongArtUrl());
79 sqlStmt.bindString(i++, song.getSongStreamUrl());
80
81 sqlStmt.bindString(i++, song.getId());
82 // Can't use executeUpdateDelete on API < 11
83 sqlStmt.execute();
84 long rowsUpdated = getChanges(db);
85
86 if (rowsUpdated == 0L) {
87 sqlStmt = db.compileStatement(getInsertSql());
88 i = 1;
89 sqlStmt.bindLong(i++, System.currentTimeMillis());
90 sqlStmt.bindString(i++, song.getId());
91
92 sqlStmt.bindString(i++, song.getTitle());
93 sqlStmt.bindString(i++, song.getAlbum());
94 sqlStmt.bindString(i++, song.getAlbumId());
95 sqlStmt.bindString(i++, song.getAlbumArtist());
96
97 sqlStmt.bindString(i++, song.getArtist());
98 sqlStmt.bindString(i++, song.getArtistId());
99 sqlStmt.bindString(i++, song.getGenre());
100 sqlStmt.bindString(i++, getGenreId(song.getGenre()));
101
102 sqlStmt.bindLong(i++, song.getYear());
103 sqlStmt.bindLong(i++, song.getDiscNumber());
104 sqlStmt.bindLong(i++, song.getTrack());
105 sqlStmt.bindLong(i++, song.getDuration());
106
107 sqlStmt.bindLong(i++, song.getSize());
108 sqlStmt.bindLong(i++, song.getBitRate());
109 sqlStmt.bindString(i++, song.getSuffix());
110 sqlStmt.bindString(i++, song.getContentType());
111
112 sqlStmt.bindString(i++, song.getSongUrl());
113 sqlStmt.bindString(i++, song.getSongArtUrl());
114 sqlStmt.bindString(i++, song.getSongStreamUrl());
115
116 long rowId = sqlStmt.executeInsert();
117 isSuccess = rowId != -1;
118 } else {
119 isSuccess = rowsUpdated == 1;
120 }
121 return isSuccess;
122 }
123
124 @Override
125 public String onGetInsertSql() {
126 return "INSERT INTO " + Tables.SONGS + "(" +
127 Songs.UPDATED + ", " +
128 Songs.SONG_ID + ", " +
129
130 Songs.SONG_TITLE + ", " +
131 Songs.SONG_ALBUM + ", " +
132 Songs.SONG_ALBUM_ID + ", " +
133 Songs.SONG_ALBUM_ARTIST + ", " +
134
135 Songs.SONG_ARTIST + ", " +
136 Songs.SONG_ARTIST_ID + ", " +
137 Songs.SONG_GENRE + ", " +
138 Songs.SONG_GENRE_ID + ", " +
139
140 Songs.SONG_YEAR + ", " +
141 Songs.SONG_DISC_NUMBER + ", " +
142 Songs.SONG_TRACK + ", " +
143 Songs.SONG_DURATION + ", " +
144
145 Songs.SONG_SIZE + ", " +
146 Songs.SONG_BIT_RATE + ", " +
147 Songs.SONG_SUFFIX + ", " +
148 Songs.SONG_CONTENT_TYPE + ", " +
149
150 Songs.SONG_URL + ", " +
151 Songs.SONG_ART_URL + ", " +
152 Songs.SONG_STREAM_URL +
153
154 ") VALUES (?, ?, " +
155 "?, ?, ?, ?, " +
156 "?, ?, ?, ?, " +
157 "?, ?, ?, ?, " +
158 "?, ?, ?, ?, " +
159 "?, ?, ?" +
160 ")";
161 }
162
163 @Override
164 public String onGetUpdateSql() {
165 return "UPDATE " + Tables.SONGS + " SET " +
166 Songs.UPDATED + "=?, " +
167
168 Songs.SONG_TITLE + "=?, " +
169 Songs.SONG_ALBUM + "=?, " +
170 Songs.SONG_ALBUM_ID + "=?, " +
171 Songs.SONG_ALBUM_ARTIST + "=?, " +
172
173 Songs.SONG_ARTIST + "=?, " +
174 Songs.SONG_ARTIST_ID + "=?, " +
175 Songs.SONG_GENRE + "=?, " +
176 Songs.SONG_GENRE_ID + "=?, " +
177
178 Songs.SONG_YEAR + "=?, " +
179 Songs.SONG_DISC_NUMBER + "=?, " +
180 Songs.SONG_TRACK + "=?, " +
181 Songs.SONG_DURATION + "=?, " +
182
183 Songs.SONG_SIZE + "=?, " +
184 Songs.SONG_BIT_RATE + "=?, " +
185 Songs.SONG_SUFFIX + "=?, " +
186 Songs.SONG_CONTENT_TYPE + "=?, " +
187
188 Songs.SONG_URL + "=?, " +
189 Songs.SONG_ART_URL + "=?, " +
190 Songs.SONG_STREAM_URL + "=? " +
191
192 "WHERE " + Songs.SONG_ID + "=?";
193 }
194}
0195
=== modified file 'src/com/ubuntuone/android/music/service/MusicService.java'
--- src/com/ubuntuone/android/music/service/MusicService.java 2012-11-08 23:02:13 +0000
+++ src/com/ubuntuone/android/music/service/MusicService.java 2012-11-21 17:34:22 +0000
@@ -384,7 +384,7 @@
384 384
385 public synchronized void resume() {385 public synchronized void resume() {
386 try {386 try {
387 if (UbuntuOneMusic.DEBUG_SHOULD_PLAY) {387 if (UbuntuOneMusic.SHOULD_PLAY) {
388 mMediaPlayer.start();388 mMediaPlayer.start();
389 }389 }
390 setPlayerState(STARTED);390 setPlayerState(STARTED);
@@ -594,7 +594,7 @@
594 mMediaPlayer.seekTo(position);594 mMediaPlayer.seekTo(position);
595 }595 }
596 596
597 if (UbuntuOneMusic.DEBUG_SHOULD_PLAY) {597 if (UbuntuOneMusic.SHOULD_PLAY) {
598 mMediaPlayer.start();598 mMediaPlayer.start();
599 }599 }
600 setPlayerState(STARTED);600 setPlayerState(STARTED);
601601
=== modified file 'src/com/ubuntuone/android/music/service/SyncService.java'
--- src/com/ubuntuone/android/music/service/SyncService.java 2012-11-08 14:14:54 +0000
+++ src/com/ubuntuone/android/music/service/SyncService.java 2012-11-21 17:34:22 +0000
@@ -21,32 +21,32 @@
2121
22package com.ubuntuone.android.music.service;22package com.ubuntuone.android.music.service;
2323
24import static com.ubuntuone.android.music.util.LogUtils.LOGD;
25import static com.ubuntuone.android.music.util.LogUtils.LOGE;
26import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;24import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
27
28import java.util.ArrayList;
29
30import android.app.IntentService;25import android.app.IntentService;
31import android.content.ContentResolver;26import android.content.ContentResolver;
32import android.content.ContentValues;
33import android.content.Context;27import android.content.Context;
34import android.content.Intent;28import android.content.Intent;
35import android.database.Cursor;29import android.database.Cursor;
36import android.net.Uri;30import android.database.sqlite.SQLiteDatabase;
37import android.os.Bundle;31import android.os.Bundle;
38import android.os.ResultReceiver;32import android.os.ResultReceiver;
39import android.util.Log;33import android.util.Log;
4034
41import com.ubuntuone.android.music.R;35import com.ubuntuone.android.music.R;
42import com.ubuntuone.android.music.UbuntuOneMusic;36import com.ubuntuone.android.music.UbuntuOneMusic;
43import com.ubuntuone.android.music.provider.MusicContentValues;
44import com.ubuntuone.android.music.provider.MusicContract.Albums;37import com.ubuntuone.android.music.provider.MusicContract.Albums;
45import com.ubuntuone.android.music.provider.MusicContract.Artists;38import com.ubuntuone.android.music.provider.MusicContract.Artists;
46import com.ubuntuone.android.music.provider.MusicContract.Playlists;39import com.ubuntuone.android.music.provider.MusicContract.Playlists;
47import com.ubuntuone.android.music.provider.MusicContract.Songs;40import com.ubuntuone.android.music.provider.MusicContract.Songs;
48import com.ubuntuone.android.music.provider.MusicContract.SyncColumns;41import com.ubuntuone.android.music.provider.MusicContract.SyncColumns;
42import com.ubuntuone.android.music.provider.MusicDatabase;
49import com.ubuntuone.android.music.provider.MusicProviderUtils;43import com.ubuntuone.android.music.provider.MusicProviderUtils;
44import com.ubuntuone.android.music.provider.dao.AlbumDao;
45import com.ubuntuone.android.music.provider.dao.ArtistDao;
46import com.ubuntuone.android.music.provider.dao.GenreDao;
47import com.ubuntuone.android.music.provider.dao.PlaylistDao;
48import com.ubuntuone.android.music.provider.dao.PlaylistSongDao;
49import com.ubuntuone.android.music.provider.dao.SongDao;
50import com.ubuntuone.android.music.util.AccountUtils;50import com.ubuntuone.android.music.util.AccountUtils;
51import com.ubuntuone.android.music.util.UIUtils;51import com.ubuntuone.android.music.util.UIUtils;
52import com.ubuntuone.api.music.U1MusicAPI;52import com.ubuntuone.api.music.U1MusicAPI;
@@ -73,7 +73,8 @@
73 public static final int SYNC_STARTED = 1;73 public static final int SYNC_STARTED = 1;
74 public static final int SYNC_PROGRESS = 2;74 public static final int SYNC_PROGRESS = 2;
75 public static final int SYNC_FINISHED = 3;75 public static final int SYNC_FINISHED = 3;
7676
77 private static final boolean DIRECT_SQL = true;
77 78
78 private static int sSyncStatus = 0;79 private static int sSyncStatus = 0;
79 80
@@ -104,7 +105,7 @@
104 mReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);105 mReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
105 if (action != null && ACTION_SYNC_MUSIC_METADATA.equals(action)) {106 if (action != null && ACTION_SYNC_MUSIC_METADATA.equals(action)) {
106 mTimeSyncStarted = System.currentTimeMillis();107 mTimeSyncStarted = System.currentTimeMillis();
107 if (mApi != null && UbuntuOneMusic.DEBUG_SHOULD_SYNC) {108 if (mApi != null && UbuntuOneMusic.SHOULD_SYNC) {
108 sSyncStatus = SYNC_STARTED;109 sSyncStatus = SYNC_STARTED;
109 if (mReceiver != null) mReceiver.send(SYNC_STARTED, Bundle.EMPTY);110 if (mReceiver != null) mReceiver.send(SYNC_STARTED, Bundle.EMPTY);
110 syncMusicMetadata();111 syncMusicMetadata();
@@ -122,37 +123,49 @@
122 syncSongs();123 syncSongs();
123 syncPlaylists();124 syncPlaylists();
124 syncPlaylistSongs();125 syncPlaylistSongs();
125 // Don't purge if network has gone away.126 // Purge only if network connection still present.
126 if (UIUtils.isNetworkConnected(this)) {127 if (UIUtils.isNetworkConnected(this)) {
127 purgeInvalidData(mTimeSyncStarted);128 purgeInvalidData(mTimeSyncStarted);
128 }129 }
129 }130 }
130 131
131 private void syncArtists() {132 private void syncArtists() {
133 final long timeMillis = System.currentTimeMillis();
132 mApi.getArtists(mArtistListener);134 mApi.getArtists(mArtistListener);
135 final long nowMillis = System.currentTimeMillis();
136 Log.i(TAG, "Artists sync took " + (nowMillis - timeMillis) + "ms");
133 }137 }
134 138
135 private void syncAlbums() {139 private void syncAlbums() {
140 final long timeMillis = System.currentTimeMillis();
136 mApi.getAlbums(mAlbumListener);141 mApi.getAlbums(mAlbumListener);
142 final long nowMillis = System.currentTimeMillis();
143 Log.i(TAG, "Albums sync took " + (nowMillis - timeMillis) + "ms");
137 }144 }
138 145
139 private void syncSongs() {146 private void syncSongs() {
147 final long timeMillis = System.currentTimeMillis();
140 mApi.getSongs(mSongListener);148 mApi.getSongs(mSongListener);
149 final long nowMillis = System.currentTimeMillis();
150 Log.i(TAG, "Songs sync took " + (nowMillis - timeMillis) + "ms");
141 }151 }
142 152
143 private void syncPlaylists() {153 private void syncPlaylists() {
154 final long timeMillis = System.currentTimeMillis();
144 mApi.getPlaylists(mPlaylistListener);155 mApi.getPlaylists(mPlaylistListener);
156 final long nowMillis = System.currentTimeMillis();
157 Log.i(TAG, "Playlists sync took " + (nowMillis - timeMillis) + "ms");
145 }158 }
146 159
147 private void syncPlaylistSongs() {160 private void syncPlaylistSongs() {
161 final long timeMillis = System.currentTimeMillis();
148 Cursor cursor = null;162 Cursor cursor = null;
149 try {163 try {
150 String[] projection = new String[] { Playlists.PLAYLIST_ID };164 String[] projection = new String[] { Playlists.PLAYLIST_ID };
151 cursor = getContentResolver().query(Playlists.CONTENT_URI, projection,165 cursor = getContentResolver().query(Playlists.CONTENT_URI, projection,
152 null, null, null);166 null, null, null);
153 while (cursor.moveToNext()) {167 while (cursor.moveToNext()) {
154 String playlistId = cursor.getString(168 String playlistId = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_ID));
155 cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID));
156 if (MusicProviderUtils.QUEUE_ID.equals(playlistId)) continue;169 if (MusicProviderUtils.QUEUE_ID.equals(playlistId)) continue;
157 mPlaylistSongListener.setPlaylist(playlistId);170 mPlaylistSongListener.setPlaylist(playlistId);
158 mApi.getPlaylist(playlistId, mPlaylistSongListener);171 mApi.getPlaylist(playlistId, mPlaylistSongListener);
@@ -160,163 +173,197 @@
160 } finally {173 } finally {
161 if (cursor != null) cursor.close();174 if (cursor != null) cursor.close();
162 }175 }
176 final long nowMillis = System.currentTimeMillis();
177 Log.i(TAG, "Playlist songs sync took " + (nowMillis - timeMillis) + "ms");
163 }178 }
164 179
165 private U1ArtistListener mArtistListener = new U1ArtistListener() {180 private U1ArtistListener mArtistListener = new U1ArtistListener() {
181 private SQLiteDatabase db;
182 private ArtistDao artistDao = new ArtistDao();
183 private Bundle progressBundle = new Bundle();
184 private Failure failure = null;
166 private int artistCount = 0;185 private int artistCount = 0;
167 private int artistAlbumCount = 0;
168
169 private Bundle progressBundle = new Bundle();
170 186
171 @Override187 @Override
172 public void onStart() {188 public void onStart() {
173 LOGD(TAG, "Syncing artists...");189 Log.d(TAG, "Syncing artists...");
190 if (DIRECT_SQL) {
191 db = new MusicDatabase(SyncService.this).getWritableDatabase();
192 db.beginTransaction();
193 }
174 progressBundle.putInt(EXTRA_LOADER_ID, R.id.artist_loader_id);194 progressBundle.putInt(EXTRA_LOADER_ID, R.id.artist_loader_id);
175 }195 }
176196
177 @Override197 @Override
178 public void onSuccess(U1Artist artist) {198 public void onSuccess(U1Artist artist) {
179 artistCount++;199 artistCount++;
180 ContentValues values = MusicContentValues.from(artist);200 if (DIRECT_SQL) {
181 Uri artistUri = Artists.buildArtistUri(artist.getId());201 artistDao.updateOrInsert(db, artist);
182 int count = mResolver.update(artistUri, values, null, null);202 } else {
183 if (count == 0) {203 artistDao.updateOrInsert(mResolver, artist);
184 mResolver.insert(Artists.CONTENT_URI, values);
185 }
186 // Insert artist albums.
187 ArrayList<ContentValues> albumsValues = MusicContentValues.albumsFrom(artist);
188 for (ContentValues albumValues : albumsValues) {
189 Uri artistAlbumUri = Artists.buildAlbumUri(
190 artist.getId(), albumValues.getAsString(Albums.ALBUM_ID));
191 artistAlbumCount++;
192 int count2 = mResolver.update(artistAlbumUri, albumValues, null, null);
193 if (count2 == 0) {
194 mResolver.insert(artistAlbumUri, albumValues);
195 }
196 }204 }
197 mReceiver.send(SYNC_PROGRESS, progressBundle);205 mReceiver.send(SYNC_PROGRESS, progressBundle);
198 }206 }
199207
200 @Override208 @Override
201 public void onFailure(Failure failure) {209 public void onFailure(Failure failure) {
202 LOGE(TAG, String.format("Failed to get artists: %d -- %s",210 this.failure = failure;
211 Log.e(TAG, String.format("Failed to get artists: %d -- %s",
203 failure.getStatusCode(), failure.getMessage()));212 failure.getStatusCode(), failure.getMessage()));
204 }213 }
205214
206 @Override215 @Override
207 public void onFinish() {216 public void onFinish() {
208 LOGD(TAG, String.format("Finished syncing artists " +217 if (DIRECT_SQL) {
209 "(got %d artists, %d artist albums).", artistCount, artistAlbumCount));218 if (failure == null) db.setTransactionSuccessful();
219 db.endTransaction();
220 db.close();
221 }
222 Log.d(TAG, String.format("Finished syncing artists " +
223 "(got %d artists).", artistCount));
210 }224 }
211 };225 };
212 226
213 private U1AlbumListener mAlbumListener = new U1AlbumListener() {227 private U1AlbumListener mAlbumListener = new U1AlbumListener() {
228 private SQLiteDatabase db;
229 private AlbumDao albumDao = new AlbumDao();
230 private Bundle progressBundle = new Bundle();
231 private Failure failure = null;
214 private int albumCount = 0;232 private int albumCount = 0;
215 233
216 private Bundle progressBundle = new Bundle();
217
218 @Override234 @Override
219 public void onStart() {235 public void onStart() {
220 LOGD(TAG, "Syncing albums...");236 Log.d(TAG, "Syncing albums...");
237 if (DIRECT_SQL) {
238 db = new MusicDatabase(SyncService.this).getWritableDatabase();
239 db.beginTransaction();
240 }
221 progressBundle.putInt(EXTRA_LOADER_ID, R.id.album_loader_id);241 progressBundle.putInt(EXTRA_LOADER_ID, R.id.album_loader_id);
222 }242 }
223 243
224 @Override244 @Override
225 public void onSuccess(U1Album album) {245 public void onSuccess(U1Album album) {
226 albumCount++;246 albumCount++;
227 ContentValues values = MusicContentValues.from(album);247 if (DIRECT_SQL) {
228 Uri albumUri = Albums.buildAlbumUri(album.getId());248 albumDao.updateOrInsert(db, album);
229 int count = mResolver.update(albumUri, values, null, null);249 } else {
230 if (count == 0) {250 albumDao.updateOrInsert(mResolver, album);
231 mResolver.insert(Albums.CONTENT_URI, values);
232 }251 }
233 mReceiver.send(SYNC_PROGRESS, progressBundle);252 mReceiver.send(SYNC_PROGRESS, progressBundle);
234 }253 }
235254
236 @Override255 @Override
237 public void onFailure(Failure failure) {256 public void onFailure(Failure failure) {
238 super.onFailure(failure);257 this.failure = failure;
239 LOGE(TAG, String.format("Failed to get albums: %d -- %s",258 Log.e(TAG, String.format("Failed to get albums: %d -- %s",
240 failure.getStatusCode(), failure.getMessage()));259 failure.getStatusCode(), failure.getMessage()));
241 }260 }
242 261
243 @Override262 @Override
244 public void onFinish() {263 public void onFinish() {
245 LOGD(TAG, String.format("Finished syncing albums (got %s albums).",264 if (DIRECT_SQL) {
265 if (failure == null) db.setTransactionSuccessful();
266 db.endTransaction();
267 db.close();
268 }
269 Log.d(TAG, String.format("Finished syncing albums (got %s albums).",
246 albumCount));270 albumCount));
247 }271 }
248 };272 };
249 273
250 private U1SongListener mSongListener = new U1SongListener() {274 private U1SongListener mSongListener = new U1SongListener() {
275 private SQLiteDatabase db;
276 private SongDao songDao = new SongDao();
277 private GenreDao genreDao = new GenreDao();
278 private Bundle progressBundle = new Bundle();
279 private Failure failure = null;
251 private int songCount = 0;280 private int songCount = 0;
252 281
253 private Bundle progressBundle = new Bundle();
254
255 @Override282 @Override
256 public void onStart() {283 public void onStart() {
257 LOGD(TAG, "Syncing songs...");284 Log.d(TAG, "Syncing songs...");
285 if (DIRECT_SQL) {
286 db = new MusicDatabase(SyncService.this).getWritableDatabase();
287 db.beginTransaction();
288 }
258 progressBundle.putInt(EXTRA_LOADER_ID, R.id.song_loader_id);289 progressBundle.putInt(EXTRA_LOADER_ID, R.id.song_loader_id);
259 }290 }
260 291
261 @Override292 @Override
262 public void onSuccess(U1Song song) {293 public void onSuccess(U1Song song) {
263 songCount++;294 songCount++;
264 ContentValues values = MusicContentValues.from(song);295 if (DIRECT_SQL) {
265 Uri songUri = Songs.buildSongUri(song.getId());296 if (songDao.updateOrInsert(db, song)) {
266 int count = mResolver.update(songUri, values, null, null);297 genreDao.updateOrInsert(db, song.getGenre());
267 if (count == 0) {298 }
268 mResolver.insert(Songs.CONTENT_URI, values);299 } else {
300 songDao.updateOrInsert(mResolver, song);
269 }301 }
270 mReceiver.send(SYNC_PROGRESS, progressBundle);302 mReceiver.send(SYNC_PROGRESS, progressBundle);
271 }303 }
272304
273 @Override305 @Override
274 public void onFailure(Failure failure) {306 public void onFailure(Failure failure) {
275 super.onFailure(failure);307 this.failure = failure;
276 LOGE(TAG, String.format("Failed to get songs: %d -- %s",308 Log.e(TAG, String.format("Failed to get songs: %d -- %s",
277 failure.getStatusCode(), failure.getMessage()));309 failure.getStatusCode(), failure.getMessage()));
278 }310 }
279 311
280 @Override312 @Override
281 public void onFinish() {313 public void onFinish() {
282 LOGD(TAG, String.format("Finished syncing songs (got %d songs).",314 if (DIRECT_SQL) {
315 if (failure == null) db.setTransactionSuccessful();
316 db.endTransaction();
317 db.close();
318 }
319 Log.d(TAG, String.format("Finished syncing songs (got %d songs).",
283 songCount));320 songCount));
284 }321 }
285 };322 };
286 323
287 private U1PlaylistListener mPlaylistListener = new U1PlaylistListener() {324 private U1PlaylistListener mPlaylistListener = new U1PlaylistListener() {
325 private SQLiteDatabase db;
326 private PlaylistDao playlistDao = new PlaylistDao();
327 private Bundle progressBundle = new Bundle();
328 private Failure failure = null;
288 private int playlistCount = 0;329 private int playlistCount = 0;
289 330
290 private Bundle progressBundle = new Bundle();
291
292 @Override331 @Override
293 public void onStart() {332 public void onStart() {
294 LOGD(TAG, "Syncing playlists...");333 Log.d(TAG, "Syncing playlists...");
334 if (DIRECT_SQL) {
335 db = new MusicDatabase(SyncService.this).getWritableDatabase();
336 db.beginTransaction();
337 }
295 progressBundle.putInt(EXTRA_LOADER_ID, R.id.playlist_loader_id);338 progressBundle.putInt(EXTRA_LOADER_ID, R.id.playlist_loader_id);
296 }339 }
297 340
298 @Override341 @Override
299 public void onSuccess(U1Playlist playlist) {342 public void onSuccess(U1Playlist playlist) {
300 playlistCount++;343 playlistCount++;
301 ContentValues values = MusicContentValues.from(playlist);344 if (DIRECT_SQL) {
302 Uri playlistUri = Playlists.buildPlaylistUri(playlist.getId());345 playlistDao.updateOrInsert(db, playlist);
303 int count = mResolver.update(playlistUri, values, null, null);346 } else {
304 if (count == 0) {347 playlistDao.updateOrInsert(mResolver, playlist);
305 mResolver.insert(Playlists.CONTENT_URI, values);
306 }348 }
307 mReceiver.send(SYNC_PROGRESS, progressBundle);349 mReceiver.send(SYNC_PROGRESS, progressBundle);
308 }350 }
309351
310 @Override352 @Override
311 public void onFailure(Failure failure) {353 public void onFailure(Failure failure) {
312 super.onFailure(failure);354 this.failure = failure;
313 LOGE(TAG, String.format("Failed to get playlists: %d -- %s",355 Log.e(TAG, String.format("Failed to get playlists: %d -- %s",
314 failure.getStatusCode(), failure.getMessage()));356 failure.getStatusCode(), failure.getMessage()));
315 }357 }
316 358
317 @Override359 @Override
318 public void onFinish() {360 public void onFinish() {
319 LOGD(TAG, String.format("Finished syncing playlists (got %d playlists).",361 if (DIRECT_SQL) {
362 if (failure == null) db.setTransactionSuccessful();
363 db.endTransaction();
364 db.close();
365 }
366 Log.d(TAG, String.format("Finished syncing playlists (got %d playlists).",
320 playlistCount));367 playlistCount));
321 }368 }
322 };369 };
@@ -330,35 +377,46 @@
330 }377 }
331 378
332 private PlaylistSongListener mPlaylistSongListener = new PlaylistSongListener() {379 private PlaylistSongListener mPlaylistSongListener = new PlaylistSongListener() {
380 private SQLiteDatabase db;
381 private PlaylistSongDao playlistSongDao = new PlaylistSongDao();
382 private Failure failure = null;
333 private int playlistSongCount = 0;383 private int playlistSongCount = 0;
334 384
335 @Override385 @Override
336 public void onStart() {386 public void onStart() {
337 playlistSongCount = 0; // This listener is reused, so reset.387 playlistSongCount = 0; // This listener is reused, so reset.
338 LOGD(TAG, "Syncing playlist songs...");388 Log.d(TAG, "Syncing playlist songs...");
389 if (DIRECT_SQL) {
390 db = new MusicDatabase(SyncService.this).getWritableDatabase();
391 db.beginTransaction();
392 }
339 }393 }
340 394
341 @Override395 @Override
342 public void onSuccess(U1Song song) {396 public void onSuccess(U1Song song) {
343 playlistSongCount++;397 playlistSongCount++;
344 ContentValues values = MusicContentValues.from(mPlaylistId, song.getId());398 if (DIRECT_SQL) {
345 Uri playlistSongsUri = Playlists.buildPlaylistSongUri(mPlaylistId, song.getId());399 playlistSongDao.updateOrInsert(db, mPlaylistId, song.getId());
346 int count = mResolver.update(playlistSongsUri, values, null, null);400 } else {
347 if (count == 0) {401 playlistSongDao.updateOrInsert(mResolver, mPlaylistId, song);
348 mResolver.insert(playlistSongsUri, values);
349 }402 }
350 }403 }
351404
352 @Override405 @Override
353 public void onFailure(Failure failure) {406 public void onFailure(Failure failure) {
354 super.onFailure(failure);407 this.failure = failure;
355 LOGE(TAG, String.format("Failed to get playlist songs: %d -- %s",408 Log.e(TAG, String.format("Failed to get playlist songs: %d -- %s",
356 failure.getStatusCode(), failure.getMessage()));409 failure.getStatusCode(), failure.getMessage()));
357 }410 }
358 411
359 @Override412 @Override
360 public void onFinish() {413 public void onFinish() {
361 LOGD(TAG, String.format("Finished syncing playlist songs (got %s playlist songs).",414 if (DIRECT_SQL) {
415 if (failure == null) db.setTransactionSuccessful();
416 db.endTransaction();
417 db.close();
418 }
419 Log.d(TAG, String.format("Finished syncing playlist songs (got %s playlist songs).",
362 playlistSongCount));420 playlistSongCount));
363 }421 }
364 };422 };
365423
=== modified file 'src/com/ubuntuone/android/music/ui/HomeActivity.java'
--- src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-08 14:14:54 +0000
+++ src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-21 17:34:22 +0000
@@ -192,7 +192,7 @@
192 mService.register(HomeActivity.this);192 mService.register(HomeActivity.this);
193 }193 }
194 };194 };
195 if (UbuntuOneMusic.DEBUG_SHOULD_BIND) {195 if (UbuntuOneMusic.SHOULD_BIND) {
196 bindService(service, mConn, BIND_AUTO_CREATE | BIND_IMPORTANT);196 bindService(service, mConn, BIND_AUTO_CREATE | BIND_IMPORTANT);
197 }197 }
198 198
199199
=== added file 'test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java'
--- test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java 1970-01-01 00:00:00 +0000
+++ test/src/com/ubuntuone/android/music/UbuntuOneMusicTest.java 2012-11-21 17:34:22 +0000
@@ -0,0 +1,10 @@
1package com.ubuntuone.android.music;
2
3import junit.framework.TestCase;
4
5public class UbuntuOneMusicTest extends TestCase
6{
7 public void testIsReleaseVersion() {
8 assertTrue("NOT a release version!", UbuntuOneMusic.IS_RELEASE);
9 }
10}
011
=== modified file 'test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java'
--- test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java 2012-11-13 13:58:31 +0000
+++ test/src/com/ubuntuone/android/music/provider/MusicContentValuesTest.java 2012-11-21 17:34:22 +0000
@@ -39,7 +39,7 @@
39 39
40 final U1Artist u1Artist = new U1Artist(id, artistUrl, artist,40 final U1Artist u1Artist = new U1Artist(id, artistUrl, artist,
41 artistArtUrl, albumList, songCount);41 artistArtUrl, albumList, songCount);
42 final ContentValues cv = MusicContentValues.from(u1Artist);42 final ContentValues cv = MusicContentValues.forArtist(u1Artist);
43 43
44 assertEquals(id, cv.getAsString(Artists.ARTIST_ID));44 assertEquals(id, cv.getAsString(Artists.ARTIST_ID));
45 assertEquals(artist, cv.getAsString(Artists.ARTIST_NAME));45 assertEquals(artist, cv.getAsString(Artists.ARTIST_NAME));
@@ -63,7 +63,7 @@
63 63
64 final U1Album u1Album = new U1Album(id, albumUrl, artist, artistId,64 final U1Album u1Album = new U1Album(id, albumUrl, artist, artistId,
65 title, dateAdded, albumArtUrl, year);65 title, dateAdded, albumArtUrl, year);
66 final ContentValues cv = MusicContentValues.from(u1Album);66 final ContentValues cv = MusicContentValues.forAlbum(u1Album);
67 67
68 assertEquals(id, cv.getAsString(Albums.ALBUM_ID));68 assertEquals(id, cv.getAsString(Albums.ALBUM_ID));
69 assertEquals(title, cv.getAsString(Albums.ALBUM_TITLE));69 assertEquals(title, cv.getAsString(Albums.ALBUM_TITLE));
@@ -84,7 +84,7 @@
84 final String albumId = HashUtils.md5(title+artist);84 final String albumId = HashUtils.md5(title+artist);
85 final String artistId = HashUtils.md5(artist);85 final String artistId = HashUtils.md5(artist);
86 final String genre = "Dubstep";86 final String genre = "Dubstep";
87 final String genreIds = HashUtils.md5(genre.toUpperCase());87 final String genreIds = MusicContentValues.getGenreId(genre);
88 final Integer year = 2012;88 final Integer year = 2012;
89 final Integer discNumber = 1;89 final Integer discNumber = 1;
90 final Integer track = 9;90 final Integer track = 9;
@@ -105,7 +105,7 @@
105 album, songArtUrl, genre, year, discNumber, track,105 album, songArtUrl, genre, year, discNumber, track,
106 duration, size, bitRate, artist, artistId, title, suffix,106 duration, size, bitRate, artist, artistId, title, suffix,
107 contentType, songStreamUrl, path);107 contentType, songStreamUrl, path);
108 final ContentValues cv = MusicContentValues.from(u1Song);108 final ContentValues cv = MusicContentValues.forSong(u1Song);
109 109
110 assertEquals(id, cv.getAsString(Songs.SONG_ID));110 assertEquals(id, cv.getAsString(Songs.SONG_ID));
111 assertEquals(title, cv.getAsString(Songs.SONG_TITLE));111 assertEquals(title, cv.getAsString(Songs.SONG_TITLE));
@@ -141,7 +141,7 @@
141 141
142 final U1Playlist u1Playlist = new U1Playlist(142 final U1Playlist u1Playlist = new U1Playlist(
143 id, playlistUrl, name, songCount);143 id, playlistUrl, name, songCount);
144 final ContentValues cv = MusicContentValues.from(u1Playlist);144 final ContentValues cv = MusicContentValues.forPlaylist(u1Playlist);
145 145
146 assertEquals(id, cv.getAsString(Playlists.PLAYLIST_ID));146 assertEquals(id, cv.getAsString(Playlists.PLAYLIST_ID));
147 assertEquals(name, cv.getAsString(Playlists.PLAYLIST_NAME));147 assertEquals(name, cv.getAsString(Playlists.PLAYLIST_NAME));
@@ -153,7 +153,7 @@
153 final String playlistId = "bc54b75b-0632-4438-b6a3-c90b83362562";153 final String playlistId = "bc54b75b-0632-4438-b6a3-c90b83362562";
154 final String songId ="i6aVaQDYSS6Pal0GbO4MAw";154 final String songId ="i6aVaQDYSS6Pal0GbO4MAw";
155 155
156 final ContentValues cv = MusicContentValues.from(playlistId, songId);156 final ContentValues cv = MusicContentValues.forPlaylistSong(playlistId, songId);
157 157
158 assertEquals(playlistId, cv.getAsString(PlaylistSongs.PLAYLIST_ID));158 assertEquals(playlistId, cv.getAsString(PlaylistSongs.PLAYLIST_ID));
159 assertEquals(songId, cv.getAsString(PlaylistSongs.SONG_ID));159 assertEquals(songId, cv.getAsString(PlaylistSongs.SONG_ID));
@@ -161,9 +161,9 @@
161 161
162 public void testFromGenre() {162 public void testFromGenre() {
163 final String genre = "Drum'n'Base";163 final String genre = "Drum'n'Base";
164 final String genreId = HashUtils.md5(genre.toUpperCase());164 final String genreId = MusicContentValues.getGenreId(genre);
165 165
166 final ContentValues cv = MusicContentValues.fromGenre(genre);166 final ContentValues cv = MusicContentValues.forGenre(genre);
167 167
168 assertEquals(genreId, cv.getAsString(Genres.GENRE_ID));168 assertEquals(genreId, cv.getAsString(Genres.GENRE_ID));
169 assertEquals(genre, cv.getAsString(Genres.GENRE_TITLE));169 assertEquals(genre, cv.getAsString(Genres.GENRE_TITLE));
170170
=== modified file 'test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java'
--- test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-13 13:58:31 +0000
+++ test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-21 17:34:22 +0000
@@ -4,6 +4,7 @@
44
5import android.content.ContentValues;5import android.content.ContentValues;
6import android.database.Cursor;6import android.database.Cursor;
7import android.database.sqlite.SQLiteDatabase;
7import android.net.Uri;8import android.net.Uri;
89
9import com.ubuntuone.android.music.provider.MusicContract.Albums;10import com.ubuntuone.android.music.provider.MusicContract.Albums;
@@ -13,6 +14,12 @@
13import com.ubuntuone.android.music.provider.MusicContract.Playlists;14import com.ubuntuone.android.music.provider.MusicContract.Playlists;
14import com.ubuntuone.android.music.provider.MusicContract.Songs;15import com.ubuntuone.android.music.provider.MusicContract.Songs;
15import com.ubuntuone.android.music.provider.MusicContract.SongsColumns;16import com.ubuntuone.android.music.provider.MusicContract.SongsColumns;
17import com.ubuntuone.android.music.provider.dao.AlbumDao;
18import com.ubuntuone.android.music.provider.dao.ArtistDao;
19import com.ubuntuone.android.music.provider.dao.GenreDao;
20import com.ubuntuone.android.music.provider.dao.PlaylistDao;
21import com.ubuntuone.android.music.provider.dao.PlaylistSongDao;
22import com.ubuntuone.android.music.provider.dao.SongDao;
16import com.ubuntuone.android.music.util.HashUtils;23import com.ubuntuone.android.music.util.HashUtils;
17import com.ubuntuone.android.music.util.Lists;24import com.ubuntuone.android.music.util.Lists;
18import com.ubuntuone.api.music.model.U1Album;25import com.ubuntuone.api.music.model.U1Album;
@@ -32,7 +39,7 @@
32 albumList.add("album6-album_id");39 albumList.add("album6-album_id");
33 U1Artist artist = new U1Artist("artist3-artist_id", "artist3-artist_url",40 U1Artist artist = new U1Artist("artist3-artist_id", "artist3-artist_url",
34 "artist3-artist_name", "artist3-artist_art_url", albumList, 42);41 "artist3-artist_name", "artist3-artist_art_url", albumList, 42);
35 ContentValues cv = MusicContentValues.from(artist);42 ContentValues cv = MusicContentValues.forArtist(artist);
36 43
37 Uri uri = mResolver.insert(Artists.CONTENT_URI, cv);44 Uri uri = mResolver.insert(Artists.CONTENT_URI, cv);
38 45
@@ -42,13 +49,42 @@
42 assertEquals("Wrong artist row count returned.", 1, cursor.getCount());49 assertEquals("Wrong artist row count returned.", 1, cursor.getCount());
43 assertTrue("Cursor missing rows.", cursor.moveToNext());50 assertTrue("Cursor missing rows.", cursor.moveToNext());
44 51
45 assertEquals("Wrong artist id.", "artist3-artist_id",52 assertEquals("Wrong artist id.", artist.getId(),
46 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID)));53 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID)));
47 assertEquals("Wrong artist name.", "artist3-artist_name",54 assertEquals("Wrong artist name.", artist.getArtist(),
48 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME)));55 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME)));
49 assertEquals("Wrong artist album.", "album5-album_id,album6-album_id",56 assertEquals("Wrong artist album.", MusicContentValues.getAlbumList(artist),
50 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST)));57 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST)));
51 assertEquals("Wrong artist song count.", 42,58 assertEquals("Wrong artist song count.", (int) artist.getSongCount(),
59 cursor.getInt(cursor.getColumnIndexOrThrow(Artists.SONG_COUNT)));
60
61 cursor.close();
62 }
63
64 public void testArtistDaoInsert() {
65 ArrayList<String> albumList = Lists.newArrayList();
66 albumList.add("album5-album_id");
67 albumList.add("album6-album_id");
68 U1Artist artist = new U1Artist("artist3-artist_id", "artist3-artist_url",
69 "artist3-artist_name", "artist3-artist_art_url", albumList, 42);
70 ArtistDao artistDao = new ArtistDao();
71 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
72 artistDao.updateOrInsert(db, artist);
73 db.close();
74
75 Uri uri = Artists.buildArtistUri(artist.getId());
76
77 Cursor cursor = mResolver.query(uri, Artists.DEFAULT_PROJECTION, null, null, null);
78 assertEquals("Wrong artist row count returned.", 1, cursor.getCount());
79 assertTrue("Cursor missing rows.", cursor.moveToNext());
80
81 assertEquals("Wrong artist id.", artist.getId(),
82 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_ID)));
83 assertEquals("Wrong artist name.", artist.getArtist(),
84 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ARTIST_NAME)));
85 assertEquals("Wrong artist album.", MusicContentValues.getAlbumList(artist),
86 cursor.getString(cursor.getColumnIndexOrThrow(Artists.ALBUM_LIST)));
87 assertEquals("Wrong artist song count.", (int) artist.getSongCount(),
52 cursor.getInt(cursor.getColumnIndexOrThrow(Artists.SONG_COUNT)));88 cursor.getInt(cursor.getColumnIndexOrThrow(Artists.SONG_COUNT)));
53 89
54 cursor.close();90 cursor.close();
@@ -57,7 +93,7 @@
57 public void testAlbumsInsert() {93 public void testAlbumsInsert() {
58 U1Album album = new U1Album("album5-album_id", "album5-album_url", "artist1-artist_name",94 U1Album album = new U1Album("album5-album_id", "album5-album_url", "artist1-artist_name",
59 "artist1-artist_id", "album5-album_title", 1345345345L, "album5-art-url", 2012);95 "artist1-artist_id", "album5-album_title", 1345345345L, "album5-art-url", 2012);
60 ContentValues cv = MusicContentValues.from(album);96 ContentValues cv = MusicContentValues.forAlbum(album);
61 97
62 Uri uri = mResolver.insert(Albums.CONTENT_URI, cv);98 Uri uri = mResolver.insert(Albums.CONTENT_URI, cv);
63 99
@@ -67,18 +103,47 @@
67 assertEquals("Wrong album row count returned.", 1, cursor.getCount());103 assertEquals("Wrong album row count returned.", 1, cursor.getCount());
68 assertTrue("Cursor missing rows.", cursor.moveToNext());104 assertTrue("Cursor missing rows.", cursor.moveToNext());
69 105
70 assertEquals("Wrong album id.", "album5-album_id",106 assertEquals("Wrong album id.", album.getId(),
71 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID)));107 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID)));
72 assertEquals("Wrong album title.", "album5-album_title",108 assertEquals("Wrong album title.", album.getTitle(),
73 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE)));109 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE)));
74 assertEquals("Wrong album artist name.", "artist1-artist_name",110 assertEquals("Wrong album artist name.", album.getArtist(),
75 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST)));111 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST)));
76 assertEquals("Wrong album artist id.",112 assertEquals("Wrong album artist id.", album.getArtistId(),
77 HashUtils.md5("artist1-artist_name"),113 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID)));
78 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID)));114 assertEquals("Wrong album year.", (int) album.getYear(),
79 assertEquals("Wrong album year.", 2012,115 cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR)));
80 cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR)));116 assertEquals("Wrong album date added.", (long) album.getParsedDate(),
81 assertEquals("Wrong album date added.", 1345345345L,117 cursor.getLong(cursor.getColumnIndexOrThrow(Albums.ALBUM_DATE_ADDED)));
118
119 cursor.close();
120 }
121
122 public void testAlbumDaoInsert() {
123 U1Album album = new U1Album("album5-album_id", "album5-album_url", "artist1-artist_name",
124 "artist1-artist_id", "album5-album_title", 1345345345L, "album5-art-url", 2012);
125 AlbumDao albumDao = new AlbumDao();
126 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
127 albumDao.updateOrInsert(db, album);
128 db.close();
129
130 Uri uri = Albums.buildAlbumUri(album.getId());
131
132 Cursor cursor = mResolver.query(uri, Albums.DEFAULT_PROJECTION, null, null, null);
133 assertEquals("Wrong album row count returned.", 1, cursor.getCount());
134 assertTrue("Cursor missing rows.", cursor.moveToNext());
135
136 assertEquals("Wrong album id.", album.getId(),
137 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ID)));
138 assertEquals("Wrong album title.", album.getTitle(),
139 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_TITLE)));
140 assertEquals("Wrong album artist name.", album.getArtist(),
141 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST)));
142 assertEquals("Wrong album artist id.", album.getArtistId(),
143 cursor.getString(cursor.getColumnIndexOrThrow(Albums.ALBUM_ARTIST_ID)));
144 assertEquals("Wrong album year.", (int) album.getYear(),
145 cursor.getInt(cursor.getColumnIndexOrThrow(Albums.ALBUM_YEAR)));
146 assertEquals("Wrong album date added.", (long) album.getParsedDate(),
82 cursor.getLong(cursor.getColumnIndexOrThrow(Albums.ALBUM_DATE_ADDED)));147 cursor.getLong(cursor.getColumnIndexOrThrow(Albums.ALBUM_DATE_ADDED)));
83 148
84 cursor.close();149 cursor.close();
@@ -88,9 +153,9 @@
88 U1Song song = new U1Song("song5-song_id", "song5-song_url",153 U1Song song = new U1Song("song5-song_id", "song5-song_url",
89 HashUtils.md5("album1-album_titleartist1-artist_name"), "song5-album_artist",154 HashUtils.md5("album1-album_titleartist1-artist_name"), "song5-album_artist",
90 "album1-album_title", "song5-song_art_url", "genre2", 2009, 3, 2, 315,155 "album1-album_title", "song5-song_art_url", "genre2", 2009, 3, 2, 315,
91 1024 * 1024 * 2, 256, "artist1-artist_name", "aritst1-artist_id",156 1024 * 1024 * 2, 256, "artist1-artist_name", HashUtils.md5("artist1-artist_name"),
92 "song5-song_title", "mp3", "audio/mpeg", "song5-song_stream", null);157 "song5-song_title", "mp3", "audio/mpeg", "song5-song_stream", null);
93 ContentValues cv = MusicContentValues.from(song);158 ContentValues cv = MusicContentValues.forSong(song);
94 159
95 Uri uri = mResolver.insert(Songs.CONTENT_URI, cv);160 Uri uri = mResolver.insert(Songs.CONTENT_URI, cv);
96 161
@@ -100,40 +165,96 @@
100 assertEquals("Wrong song row count returned.", 1, cursor.getCount());165 assertEquals("Wrong song row count returned.", 1, cursor.getCount());
101 assertTrue("Cursor missing rows.", cursor.moveToNext());166 assertTrue("Cursor missing rows.", cursor.moveToNext());
102 167
103 assertEquals("Wrong song id.", "song5-song_id",168 assertEquals("Wrong song id.", song.getId(),
104 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID)));169 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID)));
105 assertEquals("Wrong song title.", "song5-song_title",170 assertEquals("Wrong song title.", song.getTitle(),
106 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE)));171 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE)));
107 assertEquals("Wrong song album.", "album1-album_title",172 assertEquals("Wrong song album.", song.getAlbum(),
108 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM)));173 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM)));
109 assertEquals("Wrong song album id.",174 assertEquals("Wrong song album id.", song.getAlbumId(),
110 HashUtils.md5("album1-album_titleartist1-artist_name"),175 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID)));
111 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID)));176 assertEquals("Wrong song album artist.", song.getAlbumArtist(),
112 assertEquals("Wrong song album artist.", "song5-album_artist",177 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST)));
113 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST)));178 assertEquals("Wrong song artist.", song.getArtist(),
114 assertEquals("Wrong song artist.", "artist1-artist_name",179 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST)));
115 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST)));180 assertEquals("Wrong song artist id.", song.getArtistId(),
116 assertEquals("Wrong song artist id.", HashUtils.md5("artist1-artist_name"),181 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID)));
117 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID)));182 assertEquals("Wrong song genre.", song.getGenre(),
118 assertEquals("Wrong song genre.", "genre2",183 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE)));
119 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE)));184 assertEquals("Wrong song genre ids.", MusicContentValues.getGenreId(song.getGenre()),
120 assertEquals("Wrong song genre ids.", HashUtils.md5("genre2".toUpperCase()),185 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID)));
121 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID)));186 assertEquals("Wrong song year.", (int) song.getYear(),
122 assertEquals("Wrong song year.", 2009,187 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR)));
123 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR)));188 assertEquals("Wrong song disc number.", (int) song.getDiscNumber(),
124 assertEquals("Wrong song disc number.", 3,189 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER)));
125 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER)));190 assertEquals("Wrong song track.", (int) song.getTrack(),
126 assertEquals("Wrong song track.", 2,191 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK)));
127 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK)));192 assertEquals("Wrong song duration.", (int) song.getDuration(),
128 assertEquals("Wrong song duration.", 315,193 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION)));
129 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION)));194 assertEquals("Wrong song size.", (int) song.getSize(),
130 assertEquals("Wrong song size.", 1024 * 1024 * 2,195 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE)));
131 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE)));196 assertEquals("Wrong song bit rate.", (int) song.getBitRate(),
132 assertEquals("Wrong song bit rate.", 256,197 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE)));
133 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE)));198 assertEquals("Wrong song suffix.", song.getSuffix(),
134 assertEquals("Wrong song suffix.", "mp3",199 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX)));
135 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX)));200 assertEquals("Wrong song content type.", song.getContentType(),
136 assertEquals("Wrong song content type.", "audio/mpeg",201 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_CONTENT_TYPE)));
202 assertEquals("Wrong song last played at.", 0L,
203 cursor.getLong(cursor.getColumnIndexOrThrow(Songs.SONG_LAST_PLAYED_AT)));
204
205 cursor.close();
206 }
207
208 public void testSongDaoInsert() {
209 U1Song song = new U1Song("song5-song_id", "song5-song_url",
210 HashUtils.md5("album1-album_titleartist1-artist_name"), "song5-album_artist",
211 "album1-album_title", "song5-song_art_url", "genre2", 2009, 3, 2, 315,
212 1024 * 1024 * 2, 256, "artist1-artist_name", HashUtils.md5("artist1-artist_name"),
213 "song5-song_title", "mp3", "audio/mpeg", "song5-song_stream", null);
214 SongDao songDao = new SongDao();
215 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
216 songDao.updateOrInsert(db, song);
217 db.close();
218
219 Uri uri = Songs.buildSongUri(song.getId());
220
221 Cursor cursor = mResolver.query(uri, Songs.DEFAULT_PROJECTION, null, null, null);
222 assertEquals("Wrong song row count returned.", 1, cursor.getCount());
223 assertTrue("Cursor missing rows.", cursor.moveToNext());
224
225 assertEquals("Wrong song id.", song.getId(),
226 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ID)));
227 assertEquals("Wrong song title.", song.getTitle(),
228 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_TITLE)));
229 assertEquals("Wrong song album.", song.getAlbum(),
230 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM)));
231 assertEquals("Wrong song album id.", song.getAlbumId(),
232 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ID)));
233 assertEquals("Wrong song album artist.", song.getAlbumArtist(),
234 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ALBUM_ARTIST)));
235 assertEquals("Wrong song artist.", song.getArtist(),
236 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST)));
237 assertEquals("Wrong song artist id.", song.getArtistId(),
238 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_ARTIST_ID)));
239 assertEquals("Wrong song genre.", song.getGenre(),
240 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE)));
241 assertEquals("Wrong song genre ids.", MusicContentValues.getGenreId(song.getGenre()),
242 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_GENRE_ID)));
243 assertEquals("Wrong song year.", (int) song.getYear(),
244 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_YEAR)));
245 assertEquals("Wrong song disc number.", (int) song.getDiscNumber(),
246 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DISC_NUMBER)));
247 assertEquals("Wrong song track.", (int) song.getTrack(),
248 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_TRACK)));
249 assertEquals("Wrong song duration.", (int) song.getDuration(),
250 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_DURATION)));
251 assertEquals("Wrong song size.", (int) song.getSize(),
252 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_SIZE)));
253 assertEquals("Wrong song bit rate.", (int) song.getBitRate(),
254 cursor.getInt(cursor.getColumnIndexOrThrow(Songs.SONG_BIT_RATE)));
255 assertEquals("Wrong song suffix.", song.getSuffix(),
256 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_SUFFIX)));
257 assertEquals("Wrong song content type.", song.getContentType(),
137 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_CONTENT_TYPE)));258 cursor.getString(cursor.getColumnIndexOrThrow(Songs.SONG_CONTENT_TYPE)));
138 assertEquals("Wrong song last played at.", 0L,259 assertEquals("Wrong song last played at.", 0L,
139 cursor.getLong(cursor.getColumnIndexOrThrow(Songs.SONG_LAST_PLAYED_AT)));260 cursor.getLong(cursor.getColumnIndexOrThrow(Songs.SONG_LAST_PLAYED_AT)));
@@ -144,7 +265,7 @@
144 public void testPlaylistsInsert() {265 public void testPlaylistsInsert() {
145 U1Playlist playlist = new U1Playlist("playlist3-playlist_id", "playlist3-playlist_url",266 U1Playlist playlist = new U1Playlist("playlist3-playlist_id", "playlist3-playlist_url",
146 "playlist3-playlist_name", 10);267 "playlist3-playlist_name", 10);
147 ContentValues cv = MusicContentValues.from(playlist);268 ContentValues cv = MusicContentValues.forPlaylist(playlist);
148 269
149 Uri uri = mResolver.insert(Playlists.CONTENT_URI, cv);270 Uri uri = mResolver.insert(Playlists.CONTENT_URI, cv);
150 271
@@ -154,18 +275,44 @@
154 assertEquals("Wrong playlist row count returned.", 1, cursor.getCount());275 assertEquals("Wrong playlist row count returned.", 1, cursor.getCount());
155 assertTrue("Cursor missing rows.", cursor.moveToNext());276 assertTrue("Cursor missing rows.", cursor.moveToNext());
156 277
157 assertEquals("Wrong playlist id.", "playlist3-playlist_id",278 assertEquals("Wrong playlist id.", playlist.getId(),
158 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID)));279 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID)));
159 assertEquals("Wrong playlist name.", "playlist3-playlist_name",280 assertEquals("Wrong playlist name.", playlist.getName(),
160 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME)));281 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME)));
161 assertEquals("Wrong playlist song count.", 10,282 assertEquals("Wrong playlist song count.", (int) playlist.getSongCount(),
283 cursor.getInt(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_SONG_COUNT)));
284
285 cursor.close();
286 }
287
288 public void testPlaylistDaoInsert() {
289 U1Playlist playlist = new U1Playlist("playlist3-playlist_id", "playlist3-playlist_url",
290 "playlist3-playlist_name", 10);
291 PlaylistDao playlistDao = new PlaylistDao();
292 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
293 playlistDao.updateOrInsert(db, playlist);
294 db.close();
295
296 Uri uri = Playlists.buildPlaylistUri(playlist.getId());
297
298 Cursor cursor = mResolver.query(uri, Playlists.DEFAULT_PROJECTION, null, null, null);
299 assertEquals("Wrong playlist row count returned.", 1, cursor.getCount());
300 assertTrue("Cursor missing rows.", cursor.moveToNext());
301
302 assertEquals("Wrong playlist id.", playlist.getId(),
303 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_ID)));
304 assertEquals("Wrong playlist name.", playlist.getName(),
305 cursor.getString(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_NAME)));
306 assertEquals("Wrong playlist song count.", (int) playlist.getSongCount(),
162 cursor.getInt(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_SONG_COUNT)));307 cursor.getInt(cursor.getColumnIndexOrThrow(Playlists.PLAYLIST_SONG_COUNT)));
163 308
164 cursor.close();309 cursor.close();
165 }310 }
166 311
167 public void testPlaylistSongsInsert() {312 public void testPlaylistSongsInsert() {
168 Uri playlistSongsUri = Playlists.buildPlaylistSongsUri("playlist1-playlist_id");313 final String playlistId = "playlist1-playlist_id";
314 final String songId = "song3-song_id";
315 Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId);
169 316
170 { // Check preconditions.317 { // Check preconditions.
171 Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION,318 Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION,
@@ -175,7 +322,7 @@
175 }322 }
176 323
177 // Insert new song.324 // Insert new song.
178 ContentValues cv = MusicContentValues.from("playlist1-playlist_id", "song3-song_id");325 ContentValues cv = MusicContentValues.forPlaylistSong(playlistId, songId);
179 Uri uri = mResolver.insert(playlistSongsUri, cv);326 Uri uri = mResolver.insert(playlistSongsUri, cv);
180 327
181 assertNotNull("Inserted playlist song uri is null.", uri);328 assertNotNull("Inserted playlist song uri is null.", uri);
@@ -186,9 +333,41 @@
186 333
187 assertTrue("Cursor missing rows.", cursor.moveToPosition(2)); // move to third song334 assertTrue("Cursor missing rows.", cursor.moveToPosition(2)); // move to third song
188 335
189 assertEquals("Wrong playlist id.", "playlist1-playlist_id",336 assertEquals("Wrong playlist id.", playlistId,
190 cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID)));337 cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID)));
191 assertEquals("Wrong playlist song id.", "song3-song_id",338 assertEquals("Wrong playlist song id.", songId,
339 cursor.getString(cursor.getColumnIndexOrThrow(SongsColumns.SONG_ID)));
340
341 cursor.close();
342 }
343
344 public void testPlaylistSongDaoInsert() {
345 final String playlistId = "playlist1-playlist_id";
346 final String songId = "song3-song_id";
347 Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId);
348
349 { // Check preconditions.
350 Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION,
351 null, null, PlaylistSongs.DEFAULT_SORT);
352 assertEquals("Wrong playlist song row count returned.", 2, cursor.getCount());
353 cursor.close();
354 }
355
356 // Insert new song.
357 PlaylistSongDao playlistSongDao = new PlaylistSongDao();
358 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
359 playlistSongDao.updateOrInsert(db, playlistId, songId);
360 db.close();
361
362 Cursor cursor = mResolver.query(playlistSongsUri, PlaylistSongs.DEFAULT_PROJECTION,
363 null, null, PlaylistSongs.DEFAULT_SORT);
364 assertEquals("Wrong playlist song row count returned.", 3, cursor.getCount());
365
366 assertTrue("Cursor missing rows.", cursor.moveToPosition(2)); // move to third song
367
368 assertEquals("Wrong playlist id.", playlistId,
369 cursor.getString(cursor.getColumnIndexOrThrow(PlaylistSongs.PLAYLIST_ID)));
370 assertEquals("Wrong playlist song id.", songId,
192 cursor.getString(cursor.getColumnIndexOrThrow(SongsColumns.SONG_ID)));371 cursor.getString(cursor.getColumnIndexOrThrow(SongsColumns.SONG_ID)));
193 372
194 cursor.close();373 cursor.close();
@@ -199,11 +378,11 @@
199 String genre1 = "acid jazz";378 String genre1 = "acid jazz";
200 String genre2 = "Acid JAZZ";379 String genre2 = "Acid JAZZ";
201 380
202 ContentValues cv1 = MusicContentValues.fromGenre(genre1);381 ContentValues cv1 = MusicContentValues.forGenre(genre1);
203 Uri uri = mResolver.insert(Genres.CONTENT_URI, cv1);382 Uri uri = mResolver.insert(Genres.CONTENT_URI, cv1);
204 assertNotNull("Inserted genre uri is null.", uri);383 assertNotNull("Inserted genre uri is null.", uri);
205 384
206 ContentValues cv2 = MusicContentValues.fromGenre(genre2);385 ContentValues cv2 = MusicContentValues.forGenre(genre2);
207 Uri uri2 = mResolver.insert(Genres.CONTENT_URI, cv2);386 Uri uri2 = mResolver.insert(Genres.CONTENT_URI, cv2);
208 assertNotNull("Inserted genre uri is null.", uri2);387 assertNotNull("Inserted genre uri is null.", uri2);
209 388
@@ -213,7 +392,28 @@
213 assertEquals("Wrong genre row count returned.", 1, cursor.getCount());392 assertEquals("Wrong genre row count returned.", 1, cursor.getCount());
214 assertTrue("Cursor missing rows.", cursor.moveToNext());393 assertTrue("Cursor missing rows.", cursor.moveToNext());
215 394
216 assertEquals("Wrong genre name.", "acid jazz",395 assertEquals("Wrong genre name.", genre1,
396 cursor.getString(cursor.getColumnIndexOrThrow(Genres.GENRE_TITLE)));
397 }
398
399 public void testGenreDaoInsert() {
400 // These genres are treated as same: md5(genre.toUpperCase())
401 String genre1 = "acid jazz";
402 String genre2 = "Acid JAZZ";
403
404 GenreDao genreDao = new GenreDao();
405 SQLiteDatabase db = new MusicDatabase(getMockContext()).getWritableDatabase();
406 genreDao.updateOrInsert(db, genre1);
407 genreDao.updateOrInsert(db, genre2);
408 db.close();
409
410 Cursor cursor = mResolver.query(Genres.CONTENT_URI,
411 Genres.DEFAULT_PROJECTION, null, null, null);
412
413 assertEquals("Wrong genre row count returned.", 1, cursor.getCount());
414 assertTrue("Cursor missing rows.", cursor.moveToNext());
415
416 assertEquals("Wrong genre name.", genre1,
217 cursor.getString(cursor.getColumnIndexOrThrow(Genres.GENRE_TITLE)));417 cursor.getString(cursor.getColumnIndexOrThrow(Genres.GENRE_TITLE)));
218 }418 }
219}419}

Subscribers

People subscribed via source and target branches