Merge lp:~karni/ubuntuone-android-music/playlist-ux-and-sync into lp:ubuntuone-android-music/v2

Proposed by Michał Karnicki
Status: Merged
Approved by: Michał Karnicki
Approved revision: 32
Merged at revision: 32
Proposed branch: lp:~karni/ubuntuone-android-music/playlist-ux-and-sync
Merge into: lp:ubuntuone-android-music/v2
Prerequisite: lp:~karni/ubuntuone-android-music/added-missing-dao
Diff against target: 1525 lines (+527/-267)
25 files modified
AndroidManifest.xml (+7/-0)
res/layout/activity_playlist.xml (+0/-76)
res/layout/activity_playlists.xml (+13/-0)
res/values/ids.xml (+1/-0)
res/values/strings.xml (+5/-0)
src/com/ubuntuone/android/music/adapter/U1PlaylistAdapter.java (+7/-2)
src/com/ubuntuone/android/music/model/Song.java (+1/-1)
src/com/ubuntuone/android/music/provider/MusicContract.java (+11/-3)
src/com/ubuntuone/android/music/provider/MusicDatabase.java (+1/-0)
src/com/ubuntuone/android/music/provider/MusicProvider.java (+6/-6)
src/com/ubuntuone/android/music/provider/MusicProviderUtils.java (+70/-3)
src/com/ubuntuone/android/music/service/MusicService.java (+16/-5)
src/com/ubuntuone/android/music/service/SyncService.java (+59/-10)
src/com/ubuntuone/android/music/ui/AlbumsFragment.java (+8/-1)
src/com/ubuntuone/android/music/ui/HomeActivity.java (+50/-4)
src/com/ubuntuone/android/music/ui/PlayerFragment.java (+1/-1)
src/com/ubuntuone/android/music/ui/PlaylistActivity.java (+0/-1)
src/com/ubuntuone/android/music/ui/PlaylistsActivity.java (+148/-6)
src/com/ubuntuone/android/music/ui/PlaylistsFragment.java (+33/-111)
src/com/ubuntuone/android/music/ui/SongsFragment.java (+58/-18)
src/com/ubuntuone/android/music/ui/dialog/InfoAlertDialog.java (+12/-6)
test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java (+2/-2)
test/src/com/ubuntuone/android/music/provider/MusicProviderQueryTest.java (+4/-4)
test/src/com/ubuntuone/android/music/provider/MusicProviderUtilsTest.java (+10/-7)
test/src/com/ubuntuone/android/music/ui/SongsPageTest.java (+4/-0)
To merge this branch: bzr merge lp:~karni/ubuntuone-android-music/playlist-ux-and-sync
Reviewer Review Type Date Requested Status
Roberto Alsina (community) Approve
Review via email: mp+136731@code.launchpad.net

Commit message

Added playlist manipulation and sync.

Description of the change

This branch allows adding and removing items from playlists, as well as sync them with U1.
Create new playlist feature is pending minor rework after recent u1-server changes rolled out.

To post a comment you must log in.
Roberto Alsina (ralsina) wrote :

Looks good!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'AndroidManifest.xml'
2--- AndroidManifest.xml 2012-11-08 14:14:54 +0000
3+++ AndroidManifest.xml 2012-11-28 17:49:20 +0000
4@@ -63,6 +63,11 @@
5 android:theme="@style/Theme.Sherlock.Light" >
6 </activity>
7 <activity
8+ android:name=".ui.PlaylistsActivity"
9+ android:label="U1 Playlists"
10+ android:theme="@style/Theme.Sherlock.Light.Dialog" >
11+ </activity>
12+ <activity
13 android:name=".ui.PlayerActivity"
14 android:label="U1 Player"
15 android:screenOrientation="portrait" >
16@@ -78,6 +83,7 @@
17 android:exported="false" >
18 <intent-filter>
19 <action android:name="com.ubuntuone.android.music.ACTION_SYNC_MUSIC_METADATA" />
20+ <action android:name="com.ubuntuone.android.music.ACTION_SYNC_PLAYLISTS" />
21 </intent-filter>
22 </service>
23 <service
24@@ -87,6 +93,7 @@
25
26 <provider
27 android:name=".provider.MusicProvider"
28+ android:exported="false"
29 android:authorities="com.ubuntuone.android.music"
30 android:label="@string/app_name"
31 android:syncable="true"
32
33=== removed file 'res/layout/activity_playlist.xml'
34--- res/layout/activity_playlist.xml 2012-09-19 23:50:20 +0000
35+++ res/layout/activity_playlist.xml 1970-01-01 00:00:00 +0000
36@@ -1,76 +0,0 @@
37-<?xml version="1.0" encoding="utf-8"?>
38-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
39- xmlns:tools="http://schemas.android.com/tools"
40- android:layout_width="match_parent"
41- android:layout_height="match_parent" >
42-
43- <ImageView
44- android:id="@+id/image"
45- android:layout_width="@dimen/header_image_size"
46- android:layout_height="@dimen/header_image_size"
47- android:layout_alignParentLeft="true"
48- android:layout_alignParentTop="true"
49- android:background="@drawable/ic_action_help"
50- android:minHeight="@dimen/header_image_size"
51- android:minWidth="@dimen/header_image_size" />
52-
53- <TextView
54- android:id="@+id/text1"
55- android:layout_width="match_parent"
56- android:layout_height="wrap_content"
57- android:layout_alignTop="@id/image"
58- android:layout_toRightOf="@id/image"
59- android:gravity="top|left"
60- android:paddingLeft="4dp"
61- android:paddingTop="4dp"
62- android:singleLine="true"
63- android:textStyle="bold"
64- android:textAppearance="@android:style/TextAppearance.Medium"
65- android:textColor="@android:color/primary_text_light" />
66-
67- <TextView
68- android:id="@+id/text2"
69- android:layout_width="match_parent"
70- android:layout_height="wrap_content"
71- android:layout_below="@id/text1"
72- android:layout_toRightOf="@id/image"
73- android:gravity="top|left"
74- android:paddingLeft="4dp"
75- android:singleLine="true"
76- android:textAppearance="@android:style/TextAppearance.Small"
77- android:textColor="@android:color/tertiary_text_light" />
78-
79- <LinearLayout
80- android:layout_width="match_parent"
81- android:layout_height="wrap_content"
82- android:layout_alignBottom="@id/image"
83- android:layout_toRightOf="@id/image"
84- android:weightSum="2" >
85-
86- <Button
87- android:id="@+id/shuffle_all"
88- android:layout_width="0dp"
89- android:layout_height="wrap_content"
90- android:layout_weight="1"
91- android:text="@string/shuffle_all"
92- android:textAppearance="@android:style/TextAppearance.Small"
93- android:onClick="shuffleAll" />
94-
95- <Button
96- android:id="@+id/repeat_all"
97- android:layout_width="0dp"
98- android:layout_height="wrap_content"
99- android:layout_weight="1"
100- android:text="@string/repeat_all"
101- android:textAppearance="@android:style/TextAppearance.Small"
102- android:onClick="repeatAll" />
103- </LinearLayout>
104-
105- <FrameLayout
106- android:id="@+id/songs"
107- android:layout_width="match_parent"
108- android:layout_height="match_parent"
109- android:layout_below="@id/image" >
110- </FrameLayout>
111-
112-</RelativeLayout>
113\ No newline at end of file
114
115=== added file 'res/layout/activity_playlists.xml'
116--- res/layout/activity_playlists.xml 1970-01-01 00:00:00 +0000
117+++ res/layout/activity_playlists.xml 2012-11-28 17:49:20 +0000
118@@ -0,0 +1,13 @@
119+<?xml version="1.0" encoding="utf-8"?>
120+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
121+ xmlns:tools="http://schemas.android.com/tools"
122+ android:layout_width="match_parent"
123+ android:layout_height="match_parent" >
124+
125+ <fragment
126+ android:id="@+id/playlists"
127+ android:name="com.ubuntuone.android.music.ui.PlaylistsFragment"
128+ android:layout_width="match_parent"
129+ android:layout_height="match_parent" />
130+
131+</RelativeLayout>
132
133=== modified file 'res/values/ids.xml'
134--- res/values/ids.xml 2012-11-08 14:14:54 +0000
135+++ res/values/ids.xml 2012-11-28 17:49:20 +0000
136@@ -15,5 +15,6 @@
137 <item type="id" name="context_play" />
138 <item type="id" name="context_star" />
139 <item type="id" name="context_add_to_playlist" />
140+ <item type="id" name="context_remove_from_playlist" />
141 <item type="id" name="context_add_to_queue" />
142 </resources>
143\ No newline at end of file
144
145=== modified file 'res/values/strings.xml'
146--- res/values/strings.xml 2012-11-08 14:14:54 +0000
147+++ res/values/strings.xml 2012-11-28 17:49:20 +0000
148@@ -31,7 +31,11 @@
149 <string name="playlist_stats">%1$s songs</string>
150 <string name="playlist_title">Playlist title</string>
151 <string name="creating_playlist">Creating playlist…</string>
152+ <string name="add_to">Add to…</string>
153+ <string name="added_to_fmt">Added to %s.</string>
154+ <string name="sync_pending">Sync pending</string>
155 <string name="creating_playlist_failed_title">Cound\'t create playlist</string>
156+ <string name="updating_playlist_failed_title">Cound\'t update playlist</string>
157
158 <string name="genres_title">genres</string>
159 <string name="genres_loading">Getting genres…</string>
160@@ -56,6 +60,7 @@
161 <string name="description_play">Play</string>
162 <string name="description_star">Star</string>
163 <string name="description_add_to_playlist">Add to playlist</string>
164+ <string name="description_remove_from_playlist">Remove from playlist</string>
165 <string name="description_add_to_queue">Add to queue</string>
166
167 <string name="shuffle_all">Shuffle all</string>
168
169=== modified file 'src/com/ubuntuone/android/music/adapter/U1PlaylistAdapter.java'
170--- src/com/ubuntuone/android/music/adapter/U1PlaylistAdapter.java 2012-11-22 10:23:21 +0000
171+++ src/com/ubuntuone/android/music/adapter/U1PlaylistAdapter.java 2012-11-28 17:49:20 +0000
172@@ -157,8 +157,13 @@
173
174 String name = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_NAME));
175 int length = cursor.getInt(cursor.getColumnIndex(Playlists.PLAYLIST_SONG_COUNT));
176-
177- holder.playlistTitle.setText(name);
178+ int dirty = cursor.getInt(cursor.getColumnIndex(Playlists.DIRTY));
179+ if (dirty != 0) {
180+ holder.playlistTitle.setText(String.format("%s [%s]",
181+ name, context.getString(R.string.sync_pending)));
182+ } else {
183+ holder.playlistTitle.setText(name);
184+ }
185 // TODO Get plural string resource for item(s).
186 if (length == 0) {
187 holder.playlistSongCount.setText(String.format("No songs", length));
188
189=== modified file 'src/com/ubuntuone/android/music/model/Song.java'
190--- src/com/ubuntuone/android/music/model/Song.java 2012-11-08 14:14:54 +0000
191+++ src/com/ubuntuone/android/music/model/Song.java 2012-11-28 17:49:20 +0000
192@@ -69,7 +69,7 @@
193
194 public Song(Context context, Uri uri) {
195 ContentResolver resolver = context.getContentResolver();
196- String[] projection = Songs.DEFAULT_PROJECTION;
197+ String[] projection = Songs.getDefaultProjection();
198 Cursor cursor = null;
199 try {
200 cursor = resolver.query(uri, projection, null, null, null);
201
202=== modified file 'src/com/ubuntuone/android/music/provider/MusicContract.java'
203--- src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-21 15:03:12 +0000
204+++ src/com/ubuntuone/android/music/provider/MusicContract.java 2012-11-28 17:49:20 +0000
205@@ -153,6 +153,8 @@
206 String PLAYLIST_SONG_COUNT = "playlist_song_count";
207 /** Full URL to this playlist online. */
208 String PLAYLIST_URL = "playlist_url";
209+ /** Flag indicating playlist should be sync'ed up. */
210+ String DIRTY = "dirty";
211 }
212
213 interface PlaylistSongsColumns extends SongsColumns
214@@ -376,7 +378,7 @@
215 .buildUpon().appendPath(PATH_CACHED).build();
216
217 /** Default query projection. */
218- public static final String[] DEFAULT_PROJECTION = new String[] {
219+ private static final String[] DEFAULT_PROJECTION = new String[] {
220 Songs._ID, Songs.SONG_ID, Songs.SONG_TITLE, Songs.SONG_ALBUM,
221 Songs.SONG_ALBUM_ID, Songs.SONG_ALBUM_ARTIST,
222 Songs.SONG_ARTIST, Songs.SONG_ARTIST_ID, Songs.SONG_GENRE,
223@@ -385,6 +387,12 @@
224 Songs.SONG_BIT_RATE, Songs.SONG_SUFFIX, Songs.SONG_CONTENT_TYPE,
225 Songs.SONG_PATH, Songs.SONG_LAST_PLAYED_AT, Songs.STARRED, Songs.SONG_IS_PLAYING,
226 };
227+
228+ public static String[] getDefaultProjection() {
229+ // karni: Earn $10 and tell me why you have to return a COPY of a *static final* for it
230+ // not to change here, in MusicContract#DEFAULT_PROJECTION. Platform bug?
231+ return DEFAULT_PROJECTION.clone();
232+ }
233
234 /** Default "ORDER BY" clause. */
235 public static final String DEFAULT_SORT = SongsColumns.SONG_TITLE
236@@ -435,7 +443,7 @@
237 /** Default query projection. */
238 public static final String[] DEFAULT_PROJECTION = new String[] {
239 Playlists._ID, Playlists.PLAYLIST_ID, Playlists.PLAYLIST_NAME,
240- Playlists.PLAYLIST_SONG_COUNT, Playlists.STARRED
241+ Playlists.PLAYLIST_SONG_COUNT, Playlists.STARRED, Playlists.DIRTY
242 };
243
244 public static final String[] SONGS_DEFAULT_PROJECTION = new String[] {
245@@ -503,7 +511,7 @@
246 }
247
248 public static class PlaylistSongs implements PlaylistSongsColumns, SyncColumns,
249- SongsColumns, BaseColumns
250+ SongsColumns, StarredColumn, BaseColumns
251 {
252 public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon()
253 .appendPath(PATH_PLAYLISTS_SONGS).build();
254
255=== modified file 'src/com/ubuntuone/android/music/provider/MusicDatabase.java'
256--- src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-21 15:03:12 +0000
257+++ src/com/ubuntuone/android/music/provider/MusicDatabase.java 2012-11-28 17:49:20 +0000
258@@ -202,6 +202,7 @@
259 + PlaylistsColumns.PLAYLIST_NAME + " TEXT NOT NULL, "
260 + PlaylistsColumns.PLAYLIST_SONG_COUNT + " INTEGER NOT NULL DEFAULT 0, "
261 + PlaylistsColumns.PLAYLIST_URL + " TEXT NOT NULL, "
262+ + PlaylistsColumns.DIRTY + " INTEGER NOT NULL DEFAULT 0, "
263 + "UNIQUE (" + PlaylistsColumns.PLAYLIST_ID + ") ON CONFLICT IGNORE)");
264
265 // Create the play queue playlist.
266
267=== modified file 'src/com/ubuntuone/android/music/provider/MusicProvider.java'
268--- src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-22 10:23:21 +0000
269+++ src/com/ubuntuone/android/music/provider/MusicProvider.java 2012-11-28 17:49:20 +0000
270@@ -602,18 +602,18 @@
271 final String playlistId = Playlists.getPlaylistId(uri);
272 return builder.table(Tables.PLAYLIST_SONGS_JOIN_SONGS)
273 .where(PlaylistSongs.PLAYLIST_ID + "=?", playlistId)
274- .mapToTable(Songs._ID, Tables.SONGS)
275- .mapToTable(Songs.SONG_ID, Tables.SONGS);
276+ .mapToTable(PlaylistSongs._ID, Tables.PLAYLISTS_SONGS)
277+ .mapToTable(PlaylistSongs.SONG_ID, Tables.SONGS);
278 }
279 case PLAYLISTS_ID_SONGS_ID: {
280 final String playlistId = Playlists.getPlaylistId(uri);
281 final String songId = Playlists.getSongId(uri);
282- return builder.table(Tables.PLAYLISTS_SONGS)
283+ return builder.table(Tables.PLAYLIST_SONGS_JOIN_SONGS)
284 .where(PlaylistSongs.PLAYLIST_ID + "=?", playlistId)
285 .where(PlaylistSongs.SONG_ID + "=?", songId)
286- .mapToTable(Songs._ID, Tables.SONGS)
287- .mapToTable(Songs.SONG_ID, Tables.SONGS)
288- .mapToTable(Songs.STARRED, Tables.SONGS);
289+ .mapToTable(PlaylistSongs._ID, Tables.PLAYLISTS_SONGS)
290+ .mapToTable(PlaylistSongs.SONG_ID, Tables.SONGS)
291+ .mapToTable(PlaylistSongs.STARRED, Tables.SONGS);
292 }
293
294 case GENRES: {
295
296=== modified file 'src/com/ubuntuone/android/music/provider/MusicProviderUtils.java'
297--- src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-21 15:03:12 +0000
298+++ src/com/ubuntuone/android/music/provider/MusicProviderUtils.java 2012-11-28 17:49:20 +0000
299@@ -23,6 +23,7 @@
300
301 import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
302
303+import java.util.ArrayList;
304 import java.util.Random;
305
306 import android.content.ContentResolver;
307@@ -208,11 +209,14 @@
308
309 public static int getPlaylistSongCount(Context context, Uri playlistUri) {
310 ContentResolver resolver = context.getContentResolver();
311+ String playlistId = Playlists.getPlaylistId(playlistUri);
312+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId);
313+
314 String[] projection = new String[] { Songs._ID };
315 Cursor cursor = null;
316 int count = -1;
317 try {
318- cursor = resolver.query(playlistUri, projection, null, null, null);
319+ cursor = resolver.query(playlistSongsUri, projection, null, null, null);
320 count = (cursor != null) ? cursor.getCount() : 0;
321 } finally {
322 if (cursor != null) cursor.close();
323@@ -220,6 +224,28 @@
324 return count;
325 }
326
327+ public static ArrayList<String> getPlaylistSongIdList(Context context, String playlistId) {
328+ ContentResolver resolver = context.getContentResolver();
329+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId);
330+ ArrayList<String> songIdList = new ArrayList<String>();
331+
332+ String[] projection = new String[] { PlaylistSongs.SONG_ID };
333+ Cursor cursor = null;
334+ try {
335+ cursor = resolver.query(playlistSongsUri, projection, null, null, null);
336+ if (cursor != null && cursor.isBeforeFirst()) {
337+ while (cursor.moveToNext()) {
338+ String songId = cursor.getString(cursor.getColumnIndex(PlaylistSongs.SONG_ID));
339+ songIdList.add(songId);
340+ }
341+ }
342+ } finally {
343+ if (cursor != null) cursor.close();
344+ }
345+
346+ return songIdList;
347+ }
348+
349 public static int getPlayQueueSongCount(Context context) {
350 Uri playQueueUri = Playlists.buildPlaylistSongsUri(QUEUE_ID);
351 return getPlaylistSongCount(context, playQueueUri);
352@@ -236,14 +262,55 @@
353 Uri playQueueUri = Playlists.buildPlaylistSongsUri(MusicProviderUtils.QUEUE_ID);
354 clearPlaylist(context, playQueueUri);
355 }
356-
357+
358+ /**
359+ * Updates playlist song count, saves one request to the server upon
360+ * enqueuing content.
361+ *
362+ * @param context
363+ * The context to use.
364+ * @param playlistUri
365+ * Playlist Uri of which song count to update.
366+ */
367+ public static void updatePlaylistSongCount(Context context, Uri playlistUri) {
368+ ContentResolver resolver = context.getContentResolver();
369+ ContentValues values = new ContentValues();
370+ int songCount = MusicProviderUtils.getPlaylistSongCount(context, playlistUri);
371+ values.put(Playlists.PLAYLIST_SONG_COUNT, songCount);
372+ resolver.update(playlistUri, values, null, null);
373+ }
374+
375+ /**
376+ * Flags the playlist as dirty for sync up. Next time metadata is refreshed,
377+ * dirty playlists are first saved to the server.
378+ *
379+ * @param context
380+ * The context to use.
381+ * @param playlistUri
382+ * Uri of the playlist to flag.
383+ * @param isDirty
384+ * true to mark for sync up, false otherwise.
385+ */
386+ public static void flagPlaylistForSync(Context context, Uri playlistUri, boolean isDirty) {
387+ ContentResolver resolver = context.getContentResolver();
388+ ContentValues values = new ContentValues();
389+ values.put(Playlists.DIRTY, isDirty);
390+ resolver.update(playlistUri, values, null, null);
391+ }
392+
393 public static void enqueueSong(Context context, Uri songUri, Uri playlistUri) {
394 ContentResolver resolver = context.getContentResolver();
395 String playlistId = Playlists.getPlaylistId(playlistUri);
396 String songId = Songs.getSongId(songUri);
397+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(playlistId);
398
399 ContentValues values = MusicContentValues.forPlaylistSong(playlistId, songId);
400- resolver.insert(playlistUri, values);
401+ resolver.insert(playlistSongsUri, values);
402+
403+ if (!QUEUE_ID.equals(playlistId)) {
404+ updatePlaylistSongCount(context, playlistUri);
405+ flagPlaylistForSync(context, playlistUri, true);
406+ }
407 }
408
409 public static void enqueueSong(Context context, Uri songUri) {
410
411=== modified file 'src/com/ubuntuone/android/music/service/MusicService.java'
412--- src/com/ubuntuone/android/music/service/MusicService.java 2012-11-21 15:03:12 +0000
413+++ src/com/ubuntuone/android/music/service/MusicService.java 2012-11-28 17:49:20 +0000
414@@ -41,6 +41,7 @@
415 import android.content.Context;
416 import android.content.Intent;
417 import android.content.SharedPreferences;
418+import android.database.sqlite.SQLiteDatabaseLockedException;
419 import android.media.AudioManager;
420 import android.media.MediaPlayer;
421 import android.media.MediaPlayer.OnErrorListener;
422@@ -57,6 +58,7 @@
423 import com.ubuntuone.android.music.UbuntuOneMusic;
424 import com.ubuntuone.android.music.model.PlayerState;
425 import com.ubuntuone.android.music.model.Song;
426+import com.ubuntuone.android.music.provider.MusicContract.Songs;
427 import com.ubuntuone.android.music.provider.MusicProviderUtils;
428 import com.ubuntuone.android.music.util.UIUtils;
429 import com.ubuntuone.api.music.U1MusicAPI;
430@@ -123,9 +125,13 @@
431 this.mShufflePlay = sharedPrefs.getBoolean(SHUFFLE_PREFERENCE_KEY, false);
432 this.mRepeatPlay = sharedPrefs.getBoolean(REPEAT_PREFERENCE_KEY, false);
433
434- Uri songUri = MusicProviderUtils.getPlayingSong(this);
435- if (songUri != null) {
436- mCurrentPlaying = new Song(this, songUri);
437+ try {
438+ Uri songUri = MusicProviderUtils.getPlayingSong(this);
439+ if (songUri != null) {
440+ mCurrentPlaying = new Song(this, songUri);
441+ }
442+ } catch (SQLiteDatabaseLockedException e) {
443+ // Ignore. Assume no song has been playing.
444 }
445 }
446
447@@ -325,8 +331,13 @@
448 }
449
450 private synchronized void setCurrentPlaying(Uri uri) {
451- MusicProviderUtils.setPlayingSong(this, uri);
452- this.mCurrentPlaying = new Song(this, uri);
453+ // Make sure this is a song Uri, rather than playlist song Uri.
454+ // This has to be changed when "now playing" column is moved to the PlaylistSongs table.
455+ String songId = Songs.getSongId(uri);
456+ Uri songUri = Songs.buildSongUri(songId);
457+
458+ MusicProviderUtils.setPlayingSong(this, songUri);
459+ this.mCurrentPlaying = new Song(this, songUri);
460 callbackOnSongChanged();
461 if (mCurrentPlaying.isCompleteFileAvailable()) {
462 callbackOnSongDownload(uri, 100);
463
464=== modified file 'src/com/ubuntuone/android/music/service/SyncService.java'
465--- src/com/ubuntuone/android/music/service/SyncService.java 2012-11-28 17:49:20 +0000
466+++ src/com/ubuntuone/android/music/service/SyncService.java 2012-11-28 17:49:20 +0000
467@@ -22,12 +22,16 @@
468 package com.ubuntuone.android.music.service;
469
470 import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
471+
472+import java.util.ArrayList;
473+
474 import android.app.IntentService;
475 import android.content.ContentResolver;
476 import android.content.Context;
477 import android.content.Intent;
478 import android.database.Cursor;
479 import android.database.sqlite.SQLiteDatabase;
480+import android.net.Uri;
481 import android.os.Bundle;
482 import android.os.ResultReceiver;
483 import android.util.Log;
484@@ -58,6 +62,7 @@
485 import com.ubuntuone.api.music.model.U1Song;
486 import com.ubuntuone.api.music.request.U1AlbumListener;
487 import com.ubuntuone.api.music.request.U1ArtistListener;
488+import com.ubuntuone.api.music.request.U1CallbackListener;
489 import com.ubuntuone.api.music.request.U1PlaylistListener;
490 import com.ubuntuone.api.music.request.U1SongListener;
491
492@@ -67,6 +72,8 @@
493
494 public static final String ACTION_SYNC_MUSIC_METADATA =
495 "com.ubuntuone.android.music.ACTION_SYNC_MUSIC_METADATA";
496+ public static final String ACTION_SYNC_PLAYLISTS =
497+ "com.ubuntuone.android.music.ACTION_SYNC_PLAYLISTS";
498
499 public static final String EXTRA_RECEIVER = "result_receiver";
500 public static final String EXTRA_LOADER_ID = "loader_id";
501@@ -103,19 +110,25 @@
502 @Override
503 protected void onHandleIntent(Intent intent) {
504 final String action = intent.getAction();
505+ if (action == null) return;
506 mReceiver = intent.getParcelableExtra(EXTRA_RECEIVER);
507- if (action != null && ACTION_SYNC_MUSIC_METADATA.equals(action)) {
508- mTimeSyncStarted = System.currentTimeMillis();
509- if (mApi != null && UbuntuOneMusic.SHOULD_SYNC) {
510- sSyncStatus = SYNC_STARTED;
511- if (mReceiver != null) mReceiver.send(SYNC_STARTED, Bundle.EMPTY);
512+ mTimeSyncStarted = System.currentTimeMillis();
513+ if (mApi != null && UbuntuOneMusic.SHOULD_SYNC) {
514+ sSyncStatus = SYNC_STARTED;
515+ if (mReceiver != null) mReceiver.send(SYNC_STARTED, Bundle.EMPTY);
516+
517+ if (ACTION_SYNC_MUSIC_METADATA.equals(action)) {
518+ syncPlaylistMetadata();
519 syncMusicMetadata();
520- if (mReceiver != null) mReceiver.send(SYNC_FINISHED, Bundle.EMPTY);
521- sSyncStatus = SYNC_FINISHED;
522+ } else if (ACTION_SYNC_PLAYLISTS.equals(action)) {
523+ syncPlaylistMetadata();
524 }
525- long now = System.currentTimeMillis();
526- Log.i(TAG, "Ubuntu One music metadata sync sync took " + (now - mTimeSyncStarted) + " ms");
527+
528+ if (mReceiver != null) mReceiver.send(SYNC_FINISHED, Bundle.EMPTY);
529+ sSyncStatus = SYNC_FINISHED;
530 }
531+ long now = System.currentTimeMillis();
532+ Log.i(TAG, "Ubuntu One music metadata sync sync took " + (now - mTimeSyncStarted) + " ms");
533 }
534
535 private void syncMusicMetadata() {
536@@ -130,6 +143,10 @@
537 }
538 }
539
540+ private void syncPlaylistMetadata() {
541+ syncUpPlaylists();
542+ }
543+
544 private void syncArtists() {
545 final long timeMillis = System.currentTimeMillis();
546 mApi.getArtists(mArtistListener);
547@@ -158,6 +175,38 @@
548 Log.i(TAG, "Playlists sync took " + (nowMillis - timeMillis) + "ms");
549 }
550
551+ private void syncUpPlaylists() {
552+ final long timeMillis = System.currentTimeMillis();
553+ Cursor cursor = null;
554+ try {
555+ String[] projection = new String[] { Playlists.PLAYLIST_ID, Playlists.PLAYLIST_NAME };
556+ String selection = Playlists.DIRTY + "=1";
557+ cursor = getContentResolver().query(Playlists.CONTENT_URI,
558+ projection, selection, null, null);
559+ if (cursor != null && cursor.isBeforeFirst()) {
560+ while (cursor.moveToNext()) {
561+ final String playlistId = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_ID));
562+ String playlistName = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_NAME));
563+ ArrayList<String> songIdList = MusicProviderUtils.getPlaylistSongIdList(this, playlistId);
564+
565+ mApi.updatePlaylist(playlistId, playlistName, songIdList, new U1CallbackListener() {
566+ @Override
567+ public void onSuccess() {
568+ Log.i(TAG, "Updated playlist: " + playlistId);
569+ Uri playlistUri = Playlists.buildPlaylistUri(playlistId);
570+ MusicProviderUtils.flagPlaylistForSync(SyncService.this, playlistUri, false);
571+ // TODO Persist playlist entity from response once CSRF fix is rolled out.
572+ }
573+ });
574+ }
575+ }
576+ } finally {
577+ if (cursor != null) cursor.close();
578+ }
579+ final long nowMillis = System.currentTimeMillis();
580+ Log.i(TAG, "Playlist songs sync up took " + (nowMillis - timeMillis) + "ms");
581+ }
582+
583 private void syncPlaylistSongs() {
584 final long timeMillis = System.currentTimeMillis();
585 Cursor cursor = null;
586@@ -175,7 +224,7 @@
587 if (cursor != null) cursor.close();
588 }
589 final long nowMillis = System.currentTimeMillis();
590- Log.i(TAG, "Playlist songs sync took " + (nowMillis - timeMillis) + "ms");
591+ Log.i(TAG, "Playlist songs sync down took " + (nowMillis - timeMillis) + "ms");
592 }
593
594 private U1ArtistListener mArtistListener = new U1ArtistListener() {
595
596=== modified file 'src/com/ubuntuone/android/music/ui/AlbumsFragment.java'
597--- src/com/ubuntuone/android/music/ui/AlbumsFragment.java 2012-11-22 10:23:21 +0000
598+++ src/com/ubuntuone/android/music/ui/AlbumsFragment.java 2012-11-28 17:49:20 +0000
599@@ -25,6 +25,7 @@
600 import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
601 import android.app.Activity;
602 import android.content.Context;
603+import android.content.Intent;
604 import android.database.Cursor;
605 import android.net.Uri;
606 import android.os.Bundle;
607@@ -187,7 +188,13 @@
608 }
609
610 private boolean onAddToPlaylistContextItemSelected(int position) {
611- // TODO
612+ Cursor cursor = (Cursor) mListView.getItemAtPosition(position);
613+ String albumId = cursor.getString(cursor.getColumnIndex(Albums.ALBUM_ID));
614+ Uri albumUri = Albums.buildAlbumUri(albumId);
615+
616+ Intent intent = new Intent(getActivity(), PlaylistsActivity.class);
617+ intent.putExtra(PlaylistsActivity.EXTRA_ENQUEUE_CONTENT_ID, albumUri);
618+ startActivity(intent);
619 return true;
620 }
621
622
623=== modified file 'src/com/ubuntuone/android/music/ui/HomeActivity.java'
624--- src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-21 15:03:12 +0000
625+++ src/com/ubuntuone/android/music/ui/HomeActivity.java 2012-11-28 17:49:20 +0000
626@@ -44,8 +44,10 @@
627 import android.support.v4.app.LoaderManager;
628 import android.support.v4.content.Loader;
629 import android.support.v4.view.ViewPager;
630+import android.support.v4.widget.CursorAdapter;
631 import android.view.View;
632 import android.view.View.OnClickListener;
633+import android.widget.Adapter;
634 import android.widget.LinearLayout;
635 import android.widget.Toast;
636
637@@ -55,22 +57,26 @@
638 import com.actionbarsherlock.view.MenuItem;
639 import com.ubuntuone.android.music.R;
640 import com.ubuntuone.android.music.UbuntuOneMusic;
641+import com.ubuntuone.android.music.adapter.U1PlaylistAdapter;
642+import com.ubuntuone.android.music.adapter.U1PlaylistAdapter.Position;
643 import com.ubuntuone.android.music.adapter.holder.NowPlayingViewHolder;
644 import com.ubuntuone.android.music.model.PlayerState;
645+import com.ubuntuone.android.music.provider.MusicContract.Playlists;
646 import com.ubuntuone.android.music.provider.MusicContract.Songs;
647 import com.ubuntuone.android.music.provider.MusicProviderUtils;
648 import com.ubuntuone.android.music.service.MusicService;
649 import com.ubuntuone.android.music.service.MusicServiceBinder;
650 import com.ubuntuone.android.music.service.MusicServiceCallback;
651 import com.ubuntuone.android.music.service.SyncService;
652+import com.ubuntuone.android.music.ui.PlaylistsFragment.OnPlaylistSelectedListener;
653 import com.ubuntuone.android.music.ui.dialog.InputAlertDialog.InputAlertDialogListener;
654 import com.ubuntuone.android.music.util.AccountUtils;
655 import com.ubuntuone.android.music.util.U1ImageDownloader;
656 import com.ubuntuone.android.music.util.UIUtils;
657
658 public class HomeActivity extends SherlockFragmentActivity implements ActionBar.TabListener,
659- ViewPager.OnPageChangeListener, OnClickListener, InputAlertDialogListener,
660- MusicServiceCallback
661+ ViewPager.OnPageChangeListener, OnClickListener, OnPlaylistSelectedListener,
662+ InputAlertDialogListener, MusicServiceCallback
663 {
664 @SuppressWarnings("unused")
665 private static final String TAG = makeLogTag(HomeActivity.class);
666@@ -80,7 +86,7 @@
667 private static final int REQUEST_AUTHENTICATE = 1;
668
669 /* package */ static final int PLEASE_WAIT_DIALOG_ID = 1;
670- /* package */ static final int INFO_DIALOG_ID = 2;
671+ /* package */ static final int ERROR_DIALOG_ID = 2;
672 /* package */ static final int CREATE_PLAYLIST_DIALOG_ID = 3;
673
674 private Handler mHandler = new Handler();
675@@ -572,7 +578,47 @@
676 mShuffleAllSongsTask = null;
677 }
678 }
679-
680+
681+ @Override
682+ public void onPlaylistSelected(Adapter adapter, int position, boolean hasHeaders) {
683+ if (hasHeaders && position < U1PlaylistAdapter.Position.COUNT) {
684+ switch (position) {
685+ case Position.STARRED: {
686+ int count = MusicProviderUtils.getStarredSongCount(this);
687+ PlaylistActivity.startFrom(this, MusicProviderUtils.STARRED_ID,
688+ getString(R.string.starred), count);
689+ break;
690+ }
691+ case Position.CACHED: {
692+ int count = MusicProviderUtils.getCachedSongCount(this);
693+ PlaylistActivity.startFrom(this, MusicProviderUtils.CACHED_ID,
694+ getString(R.string.cached), count);
695+ break;
696+ }
697+ case Position.QUEUED: {
698+ PlayerActivity.startWithQueue(this);
699+ break;
700+ }
701+ }
702+ } else {
703+ if (hasHeaders) position -= Position.COUNT;
704+
705+ Cursor cursor = ((CursorAdapter) adapter).getCursor();
706+ cursor.moveToPosition(position);
707+
708+ int songCount = cursor.getInt(cursor.getColumnIndex(Playlists.PLAYLIST_SONG_COUNT));
709+ if (songCount == 0) {
710+ String title = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_NAME));
711+ String text = getString(R.string.playlist_is_empty, title);
712+ if (!isFinishing()) {
713+ Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
714+ }
715+ } else {
716+ PlaylistActivity.startFrom(this, cursor);
717+ }
718+ }
719+ }
720+
721 @Override
722 public void onClick(View v) {
723 switch (v.getId()) {
724
725=== modified file 'src/com/ubuntuone/android/music/ui/PlayerFragment.java'
726--- src/com/ubuntuone/android/music/ui/PlayerFragment.java 2012-11-08 14:14:54 +0000
727+++ src/com/ubuntuone/android/music/ui/PlayerFragment.java 2012-11-28 17:49:20 +0000
728@@ -401,7 +401,7 @@
729
730 Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(MusicProviderUtils.QUEUE_ID);
731 CursorLoader loader = new CursorLoader(getSherlockActivity(), playlistSongsUri,
732- Songs.DEFAULT_PROJECTION, null, null, PlaylistSongs.DEFAULT_SORT);
733+ Songs.getDefaultProjection(), null, null, PlaylistSongs.DEFAULT_SORT);
734
735 setIsLoading(true);
736 return loader;
737
738=== modified file 'src/com/ubuntuone/android/music/ui/PlaylistActivity.java'
739--- src/com/ubuntuone/android/music/ui/PlaylistActivity.java 2012-11-08 14:14:54 +0000
740+++ src/com/ubuntuone/android/music/ui/PlaylistActivity.java 2012-11-28 17:49:20 +0000
741@@ -58,7 +58,6 @@
742 @Override
743 protected void onCreate(Bundle savedInstanceState) {
744 super.onCreate(savedInstanceState);
745- // TODO Rename layout?
746 setContentView(R.layout.activity_collection);
747
748 mPlaylistArt = (ImageView) findViewById(R.id.image);
749
750=== modified file 'src/com/ubuntuone/android/music/ui/PlaylistsActivity.java'
751--- src/com/ubuntuone/android/music/ui/PlaylistsActivity.java 2012-11-08 14:14:54 +0000
752+++ src/com/ubuntuone/android/music/ui/PlaylistsActivity.java 2012-11-28 17:49:20 +0000
753@@ -21,16 +21,158 @@
754
755 package com.ubuntuone.android.music.ui;
756
757+import static com.ubuntuone.android.music.ui.HomeActivity.ERROR_DIALOG_ID;
758+import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
759+import android.app.Activity;
760+import android.content.ContentResolver;
761+import android.content.Intent;
762+import android.database.Cursor;
763+import android.net.Uri;
764+import android.os.AsyncTask;
765+import android.os.Bundle;
766+import android.support.v4.app.LoaderManager;
767+import android.support.v4.content.Loader;
768+import android.support.v4.widget.CursorAdapter;
769+import android.util.Log;
770+import android.widget.Adapter;
771+import android.widget.Toast;
772+
773 import com.actionbarsherlock.app.SherlockFragmentActivity;
774+import com.actionbarsherlock.view.MenuItem;
775+import com.ubuntuone.android.music.R;
776 import com.ubuntuone.android.music.provider.MusicContract.Albums;
777 import com.ubuntuone.android.music.provider.MusicContract.Artists;
778+import com.ubuntuone.android.music.provider.MusicContract.Playlists;
779 import com.ubuntuone.android.music.provider.MusicContract.Songs;
780+import com.ubuntuone.android.music.provider.MusicProviderUtils;
781+import com.ubuntuone.android.music.service.SyncService;
782+import com.ubuntuone.android.music.ui.PlaylistsFragment.OnPlaylistSelectedListener;
783+import com.ubuntuone.android.music.ui.dialog.InfoAlertDialog.InfoAlertDialogListener;
784+import com.ubuntuone.android.music.util.UIUtils;
785
786-public class PlaylistsActivity extends SherlockFragmentActivity
787+public class PlaylistsActivity extends SherlockFragmentActivity implements
788+ OnPlaylistSelectedListener, InfoAlertDialogListener
789 {
790- public static final String EXTRA_ENQUEUE_SONG_ID = Songs.SONG_ID;
791- public static final String EXTRA_ENQUEUE_ALBUM_ID = Albums.ALBUM_ID;
792- public static final String EXTRA_ENQUEUE_ARTIST_ID = Artists.ARTIST_ID;
793-
794- // TODO enqueue provided content to selected playlist, allow creating a playlist
795+ private static final String TAG = makeLogTag(PlaylistActivity.class);
796+
797+ public static final String EXTRA_ENQUEUE_CONTENT_ID = "content_uri";
798+
799+ private Uri mContentUri;
800+
801+ @Override
802+ protected void onCreate(Bundle savedInstanceState) {
803+ super.onCreate(savedInstanceState);
804+ setContentView(R.layout.activity_playlists);
805+
806+ mContentUri = getIntent().getParcelableExtra(EXTRA_ENQUEUE_CONTENT_ID);
807+
808+ if (mContentUri == null) {
809+ throw new IllegalStateException("You must provide content_uri which is " +
810+ "to be added to a playlist.");
811+ }
812+
813+ LoaderManager lm = getSupportLoaderManager();
814+ Loader<?> loader = lm.getLoader(R.id.playlist_songs_loader_id);
815+ if (loader != null) {
816+ loader.stopLoading();
817+ }
818+ }
819+
820+ @Override
821+ public boolean onOptionsItemSelected(MenuItem item) {
822+ switch (item.getItemId()) {
823+ case android.R.id.home:
824+ finish();
825+ return true;
826+
827+ default:
828+ return super.onOptionsItemSelected(item);
829+ }
830+ }
831+
832+ @Override
833+ public void onPlaylistSelected(Adapter adapter, int position, boolean hasHeaders) {
834+ if (hasHeaders) {
835+ throw new IllegalArgumentException(
836+ "PlaylistsActivity must not contain custom playlists.");
837+ }
838+
839+ Cursor cursor = ((CursorAdapter) adapter).getCursor();
840+ cursor.moveToPosition(position);
841+
842+ String playlistId = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_ID));
843+ Uri playlistUri = Playlists.buildPlaylistUri(playlistId);
844+
845+ if (mContentUri != null) {
846+ AppendToPlaylistTask appendTask = new AppendToPlaylistTask();
847+ appendTask.execute(playlistUri, mContentUri);
848+ }
849+ }
850+
851+ private class AppendToPlaylistTask extends AsyncTask<Uri, Void, Uri> {
852+ @Override
853+ protected Uri doInBackground(Uri... params) {
854+ if (params.length != 2) {
855+ throw new IllegalArgumentException(
856+ "AppendToPlaylistTask takes two arguments, playlist uri and content uri");
857+ }
858+ final Uri playlistUri = params[0];
859+ final Uri contentUri = params[1];
860+
861+ ContentResolver resolver = getContentResolver();
862+
863+ String mimeType = resolver.getType(contentUri);
864+ Activity activity = PlaylistsActivity.this;
865+ if (mimeType.equals(Artists.CONTENT_ITEM_TYPE)) {
866+ Log.e(TAG, "artist");
867+ MusicProviderUtils.enqueueArtist(activity, contentUri, playlistUri);
868+ } else if (mimeType.equals(Albums.CONTENT_ITEM_TYPE)) {
869+ Log.e(TAG, "album");
870+ MusicProviderUtils.enqueueAlbum(activity, contentUri, playlistUri);
871+ } else if (mimeType.equals(Songs.CONTENT_ITEM_TYPE)) {
872+ Log.e(TAG, "song");
873+ MusicProviderUtils.enqueueSong(activity, contentUri, playlistUri);
874+ } else {
875+ Log.e(TAG, "Unknown content uri to enqueue to playlist: " + contentUri.toString());
876+ }
877+ return playlistUri;
878+ }
879+
880+ @Override
881+ protected void onPostExecute(Uri playlistUri) {
882+ if (playlistUri == null) {
883+ Log.e(TAG, "PlaylistsActivity#AppendToPlaylistTask#onPostExecute null playlistUri");
884+ return;
885+ }
886+
887+ String playlistName = null;
888+ Cursor cursor = null;
889+ try {
890+ final String[] projection = new String[] { Playlists.PLAYLIST_NAME };
891+ cursor = getContentResolver().query(playlistUri, projection, null, null, null);
892+ if (cursor != null && cursor.moveToFirst()) {
893+ playlistName = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_NAME));
894+ }
895+ } finally {
896+ cursor.close();
897+ }
898+
899+ String msg = getString(R.string.added_to_fmt, playlistName);
900+ Toast.makeText(PlaylistsActivity.this, msg, Toast.LENGTH_SHORT).show();
901+
902+ if (UIUtils.isNetworkConnected(PlaylistsActivity.this)) {
903+ Intent syncPlaylists = new Intent(SyncService.ACTION_SYNC_PLAYLISTS);
904+ startService(syncPlaylists);
905+ }
906+
907+ finish();
908+ }
909+ }
910+
911+ @Override
912+ public void onPositiveButtonClicked(int dialogId) {
913+ if (dialogId == ERROR_DIALOG_ID) {
914+ finish();
915+ }
916+ }
917 }
918
919=== modified file 'src/com/ubuntuone/android/music/ui/PlaylistsFragment.java'
920--- src/com/ubuntuone/android/music/ui/PlaylistsFragment.java 2012-11-22 10:23:21 +0000
921+++ src/com/ubuntuone/android/music/ui/PlaylistsFragment.java 2012-11-28 17:49:20 +0000
922@@ -21,7 +21,7 @@
923
924 package com.ubuntuone.android.music.ui;
925
926-import static com.ubuntuone.android.music.ui.HomeActivity.INFO_DIALOG_ID;
927+import static com.ubuntuone.android.music.ui.HomeActivity.ERROR_DIALOG_ID;
928 import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
929
930 import java.util.ArrayList;
931@@ -30,7 +30,6 @@
932 import android.content.ContentResolver;
933 import android.content.Context;
934 import android.database.Cursor;
935-import android.net.Uri;
936 import android.os.AsyncTask;
937 import android.os.Bundle;
938 import android.support.v4.app.DialogFragment;
939@@ -44,27 +43,26 @@
940 import android.view.View;
941 import android.view.View.OnClickListener;
942 import android.view.ViewGroup;
943+import android.widget.Adapter;
944 import android.widget.Button;
945 import android.widget.ListView;
946-import android.widget.Toast;
947
948 import com.actionbarsherlock.app.SherlockFragmentActivity;
949 import com.ubuntuone.android.music.R;
950 import com.ubuntuone.android.music.UbuntuOneMusic;
951 import com.ubuntuone.android.music.adapter.U1PlaylistAdapter;
952-import com.ubuntuone.android.music.adapter.U1PlaylistAdapter.Position;
953-import com.ubuntuone.android.music.provider.MusicContract.Albums;
954-import com.ubuntuone.android.music.provider.MusicContract.Artists;
955 import com.ubuntuone.android.music.provider.MusicContract.Playlists;
956-import com.ubuntuone.android.music.provider.MusicContract.Songs;
957 import com.ubuntuone.android.music.provider.MusicProviderUtils;
958+import com.ubuntuone.android.music.provider.dao.PlaylistDao;
959 import com.ubuntuone.android.music.ui.dialog.InfoAlertDialog;
960 import com.ubuntuone.android.music.ui.dialog.InputAlertDialog;
961 import com.ubuntuone.android.music.ui.dialog.InputAlertDialog.InputAlertDialogListener;
962 import com.ubuntuone.android.music.ui.dialog.ModalAlertDialog;
963 import com.ubuntuone.api.music.U1MusicAPI;
964 import com.ubuntuone.api.music.client.Failure;
965+import com.ubuntuone.api.music.model.U1Playlist;
966 import com.ubuntuone.api.music.request.U1PlaylistCreateListener;
967+import com.ubuntuone.api.music.request.U1PlaylistListener;
968
969 public class PlaylistsFragment extends LoadingFragment<U1PlaylistAdapter> implements
970 OnClickListener, InputAlertDialogListener
971@@ -74,6 +72,8 @@
972 public static final String EXTRA_INCLUDE_CUSTOM = "include_custom";
973
974 private boolean mIncludeCustom = false;
975+
976+ private OnPlaylistSelectedListener mOnPlaylistSelectedListener;
977
978 @Override
979 public int onGetHeaderResId() {
980@@ -113,52 +113,18 @@
981 Button createPlaylist = (Button) view.findViewById(R.id.create_playlist);
982 createPlaylist.setOnClickListener(this);
983
984+ try {
985+ mOnPlaylistSelectedListener = (OnPlaylistSelectedListener) getActivity();
986+ } catch (ClassCastException e) {
987+ throw new IllegalArgumentException("Activity must implement OnPlaylistSelectedListener");
988+ }
989+
990 return view;
991 }
992
993 @Override
994 public void onListItemClick(ListView l, View v, int position, long id) {
995- showPlaylistSongs(position);
996- }
997-
998- private void showPlaylistSongs(int position) {
999- if (mIncludeCustom && position < U1PlaylistAdapter.Position.COUNT) {
1000- Context context = getActivity();
1001- switch (position) {
1002- case Position.STARRED: {
1003- int count = MusicProviderUtils.getStarredSongCount(context);
1004- PlaylistActivity.startFrom(context, MusicProviderUtils.STARRED_ID,
1005- context.getString(R.string.starred), count);
1006- break;
1007- }
1008- case Position.CACHED: {
1009- int count = MusicProviderUtils.getCachedSongCount(context);
1010- PlaylistActivity.startFrom(getActivity(), MusicProviderUtils.CACHED_ID,
1011- context.getString(R.string.cached), count);
1012- break;
1013- }
1014- case Position.QUEUED: {
1015- PlayerActivity.startWithQueue(getSherlockActivity());
1016- break;
1017- }
1018- }
1019- } else {
1020- if (mIncludeCustom) position -= Position.COUNT;
1021-
1022- Cursor cursor = mAdapter.getCursor();
1023- cursor.moveToPosition(position);
1024-
1025- int songCount = cursor.getInt(cursor.getColumnIndex(Playlists.PLAYLIST_SONG_COUNT));
1026- if (songCount == 0) {
1027- String title = cursor.getString(cursor.getColumnIndex(Playlists.PLAYLIST_NAME));
1028- String text = getString(R.string.playlist_is_empty, title);
1029- if (isResumed()) {
1030- Toast.makeText(getActivity(), text, Toast.LENGTH_SHORT).show();
1031- }
1032- } else {
1033- PlaylistActivity.startFrom(getActivity(), cursor);
1034- }
1035- }
1036+ mOnPlaylistSelectedListener.onPlaylistSelected(mAdapter, position, mIncludeCustom);
1037 }
1038
1039 @Override
1040@@ -238,6 +204,7 @@
1041 api.createPlaylist(name, emptyList, new U1PlaylistCreateListener() {
1042 @Override
1043 public void onSuccess(String playlistId) {
1044+ // TODO Persist playlist once CSRF fix is rolled out.
1045 Log.i(TAG, "Created playlist with id: " + playlistId);
1046 mPlaylistId = playlistId;
1047 }
1048@@ -250,85 +217,40 @@
1049 }
1050 });
1051
1052- // TODO karni: save the playlist
1053+ // TODO This block will be removed soon, see TODO above.
1054+ Activity activity = getSherlockActivity();
1055+ final ContentResolver resolver = activity != null ? activity.getContentResolver() : null;
1056+ if (mPlaylistId != null && resolver != null) {
1057+ api.getPlaylists(new U1PlaylistListener() {
1058+ @Override
1059+ public void onSuccess(U1Playlist playlist) {
1060+ if (mPlaylistId.equals(playlist.getId())) {
1061+ new PlaylistDao().updateOrInsert(resolver, playlist);
1062+ }
1063+ }
1064+ });
1065+ }
1066+
1067 return mPlaylistId != null;
1068 }
1069
1070 @Override
1071- protected void onPostExecute(Boolean result) {
1072+ protected void onPostExecute(Boolean created) {
1073 if (mDialogFragment != null && mDialogFragment.isAdded()) {
1074 mDialogFragment.dismiss();
1075 }
1076
1077 SherlockFragmentActivity activity = getSherlockActivity();
1078- boolean created = mPlaylistId != null;
1079 if (created && activity != null) {
1080 ((HomeActivity) activity).forcePlaylistsRefresh();
1081 } else if (!created && activity != null && !TextUtils.isEmpty(mErrorMessage)) {
1082- DialogFragment frag = InfoAlertDialog.newInstance(INFO_DIALOG_ID,
1083- R.string.creating_playlist_failed_title, mErrorMessage);
1084+ DialogFragment frag = InfoAlertDialog.newInstance(ERROR_DIALOG_ID, 0, mErrorMessage);
1085 frag.show(activity.getSupportFragmentManager(), null);
1086 }
1087 }
1088 }
1089
1090- private class AppendToPlaylistTask extends AsyncTask<Uri, Void, Boolean> {
1091- private DialogFragment mDialogFragment;
1092- private Boolean mUpdated = false;
1093- private String mErrorMessage;
1094-
1095- @Override
1096- protected void onPreExecute() {
1097- SherlockFragmentActivity activity = getSherlockActivity();
1098- if (activity != null) {
1099- mDialogFragment = ModalAlertDialog.newInstance();
1100- mDialogFragment.show(activity.getSupportFragmentManager(), "pleaseWaitDialog");
1101- }
1102- }
1103-
1104- @Override
1105- protected Boolean doInBackground(Uri... params) {
1106- if (params.length != 1) {
1107- throw new IllegalArgumentException(
1108- "AppendToPlaylistTask takes two arguments, playlist uri and content uri");
1109- }
1110- final Uri playlistUri = params[0];
1111- final Uri contentUri = params[1];
1112-
1113- Activity activity = getSherlockActivity();
1114- ContentResolver resolver = activity != null ? activity.getContentResolver() : null;
1115- if (resolver == null) return mUpdated;
1116-
1117- String mimeType = resolver.getType(contentUri);
1118- if (mimeType.equals(Artists.CONTENT_ITEM_TYPE)) {
1119- MusicProviderUtils.enqueueArtist(activity, contentUri, playlistUri);
1120- } else if (mimeType.equals(Albums.CONTENT_ITEM_TYPE)) {
1121- MusicProviderUtils.enqueueAlbum(activity, contentUri, playlistUri);
1122- } else if (mimeType.equals(Songs.CONTENT_ITEM_TYPE)) {
1123- MusicProviderUtils.enqueueSong(activity, contentUri, playlistUri);
1124- } else {
1125- Log.e(TAG, "Unknown content uri to enqueue to playlist: " + contentUri.toString());
1126- }
1127-
1128- U1MusicAPI api = UbuntuOneMusic.getInstance().getMusicApi();
1129- // TODO save playlist to server
1130- return mUpdated;
1131- }
1132-
1133- @Override
1134- protected void onPostExecute(Boolean result) {
1135- if (mDialogFragment != null && mDialogFragment.isAdded()) {
1136- mDialogFragment.dismiss();
1137- }
1138-
1139- SherlockFragmentActivity activity = getSherlockActivity();
1140- if (mUpdated && activity != null) {
1141- ((HomeActivity) activity).forcePlaylistsRefresh();
1142- } else if (!mUpdated && activity != null && !TextUtils.isEmpty(mErrorMessage)) {
1143- DialogFragment frag = InfoAlertDialog.newInstance(INFO_DIALOG_ID,
1144- R.string.creating_playlist_failed_title, mErrorMessage);
1145- frag.show(activity.getSupportFragmentManager(), null);
1146- }
1147- }
1148+ public interface OnPlaylistSelectedListener {
1149+ public void onPlaylistSelected(Adapter adapter, int position, boolean hasHeaders);
1150 }
1151 }
1152
1153=== modified file 'src/com/ubuntuone/android/music/ui/SongsFragment.java'
1154--- src/com/ubuntuone/android/music/ui/SongsFragment.java 2012-11-08 14:14:54 +0000
1155+++ src/com/ubuntuone/android/music/ui/SongsFragment.java 2012-11-28 17:49:20 +0000
1156@@ -26,7 +26,9 @@
1157 import static com.ubuntuone.android.music.ui.PlaylistActivity.EXTRA_PLAYLIST_ID;
1158 import static com.ubuntuone.android.music.util.LogUtils.makeLogTag;
1159 import android.app.Activity;
1160+import android.content.ContentResolver;
1161 import android.content.Context;
1162+import android.content.Intent;
1163 import android.database.Cursor;
1164 import android.net.Uri;
1165 import android.os.Bundle;
1166@@ -49,9 +51,11 @@
1167 import com.ubuntuone.android.music.adapter.U1SongAdapter;
1168 import com.ubuntuone.android.music.provider.MusicContract.Albums;
1169 import com.ubuntuone.android.music.provider.MusicContract.Genres;
1170+import com.ubuntuone.android.music.provider.MusicContract.PlaylistSongs;
1171 import com.ubuntuone.android.music.provider.MusicContract.Playlists;
1172 import com.ubuntuone.android.music.provider.MusicContract.Songs;
1173 import com.ubuntuone.android.music.provider.MusicProviderUtils;
1174+import com.ubuntuone.android.music.service.SyncService;
1175 import com.ubuntuone.android.music.util.UIUtils;
1176
1177 public class SongsFragment extends LoadingFragment<U1SongAdapter> implements OnClickListener
1178@@ -129,28 +133,28 @@
1179 if (mAlbumId != null) {
1180 Uri albumSongsUri = Albums.buildSongsUri(mAlbumId);
1181 loader = new CursorLoader(getSherlockActivity(), albumSongsUri,
1182- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1183+ Songs.getDefaultProjection(), null, null, Albums.DEFAULT_SONG_SORT);
1184 } else if (mPlaylistId != null) {
1185 if (mPlaylistId.equals(MusicProviderUtils.STARRED_ID)) {
1186 loader = new CursorLoader(getSherlockActivity(), Songs.STARRED_SONGS_URI,
1187- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1188+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1189 loader.onContentChanged();
1190 } else if (mPlaylistId.equals(MusicProviderUtils.CACHED_ID)) {
1191 loader = new CursorLoader(getSherlockActivity(), Songs.CACHED_SONGS_URI,
1192- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1193+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1194 loader.onContentChanged();
1195 } else {
1196 Uri playlistSongsUri = Playlists.buildPlaylistSongsUri(mPlaylistId);
1197 loader = new CursorLoader(getSherlockActivity(), playlistSongsUri,
1198- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1199+ PlaylistSongs.DEFAULT_PROJECTION.clone(), null, null, PlaylistSongs.DEFAULT_SORT);
1200 }
1201 } else if (mGenreId != null) {
1202 Uri genreSongsUri = Genres.buildGenreSongsUri(mGenreId);
1203 loader = new CursorLoader(getSherlockActivity(), genreSongsUri,
1204- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1205+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1206 } else {
1207 loader = new CursorLoader(getSherlockActivity(), Songs.CONTENT_URI,
1208- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1209+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1210 }
1211 setIsLoading(true);
1212 return loader;
1213@@ -189,15 +193,18 @@
1214 @Override
1215 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
1216 if (v.getId() == android.R.id.list) {
1217- menu.add(Menu.NONE, R.id.context_play, 0, R.string.description_play);
1218-
1219- menu.add(Menu.NONE, R.id.context_star, 0, R.string.description_star);
1220- Activity activity = getSherlockActivity();
1221- if (activity != null && UIUtils.isNetworkConnected(activity)) {
1222- menu.add(Menu.NONE, R.id.context_add_to_playlist, 0,
1223- R.string.description_add_to_playlist);
1224+ menu.add(Menu.NONE, R.id.context_play, 0,
1225+ R.string.description_play);
1226+ menu.add(Menu.NONE, R.id.context_star, 0,
1227+ R.string.description_star);
1228+ menu.add(Menu.NONE, R.id.context_add_to_playlist, 0,
1229+ R.string.description_add_to_playlist);
1230+ if (mPlaylistId != null) {
1231+ menu.add(Menu.NONE, R.id.context_remove_from_playlist, 0,
1232+ R.string.description_remove_from_playlist);
1233 }
1234- menu.add(Menu.NONE, R.id.context_add_to_queue, 0, R.string.description_add_to_queue);
1235+ menu.add(Menu.NONE, R.id.context_add_to_queue, 0,
1236+ R.string.description_add_to_queue);
1237 } else {
1238 super.onCreateContextMenu(menu, v, menuInfo);
1239 }
1240@@ -216,6 +223,8 @@
1241 return onStarContextItemSelected(position);
1242 case R.id.context_add_to_playlist:
1243 return onAddToPlaylistContextItemSelected(position);
1244+ case R.id.context_remove_from_playlist:
1245+ return onRemoveFromPlaylistContextItemSelected(position);
1246 case R.id.context_add_to_queue:
1247 return onAddToPlayQueueContextItemSelected(position);
1248 default:
1249@@ -223,6 +232,12 @@
1250 }
1251 }
1252
1253+ private void forceReload() {
1254+ int loaderId = getLoaderId();
1255+ LoaderManager lm = getSherlockActivity().getSupportLoaderManager();
1256+ lm.getLoader(loaderId).forceLoad();
1257+ }
1258+
1259 private boolean onPlayContextItemSelected(int position) {
1260 clearQueueAndPlay(mListView, position);
1261 return true;
1262@@ -238,16 +253,41 @@
1263
1264 MusicProviderUtils.toggleSongStarred(context, songUri);
1265
1266- int loaderId = getLoaderId();
1267- LoaderManager lm = getSherlockActivity().getSupportLoaderManager();
1268- lm.getLoader(loaderId).forceLoad();
1269+ forceReload();
1270 }
1271 }
1272 return true;
1273 }
1274
1275 private boolean onAddToPlaylistContextItemSelected(int position) {
1276- // TODO
1277+ Cursor cursor = (Cursor) mListView.getItemAtPosition(position);
1278+ String songId = cursor.getString(cursor.getColumnIndex(Songs.SONG_ID));
1279+ Uri songUri = Songs.buildSongUri(songId);
1280+
1281+ Intent intent = new Intent(getActivity(), PlaylistsActivity.class);
1282+ intent.putExtra(PlaylistsActivity.EXTRA_ENQUEUE_CONTENT_ID, songUri);
1283+ startActivity(intent);
1284+ return true;
1285+ }
1286+
1287+ private boolean onRemoveFromPlaylistContextItemSelected(int position) {
1288+ Cursor cursor = (Cursor) mListView.getItemAtPosition(position);
1289+ String rowId = cursor.getString(cursor.getColumnIndex(Songs._ID));
1290+
1291+ ContentResolver resolver = getActivity().getContentResolver();
1292+ String selection = Songs._ID + "=?";
1293+ String[] selectionArgs = new String[] { rowId };
1294+ resolver.delete(PlaylistSongs.CONTENT_URI, selection, selectionArgs);
1295+
1296+ Activity activity = getActivity();
1297+ Uri playlistUri = Playlists.buildPlaylistUri(mPlaylistId);
1298+ MusicProviderUtils.flagPlaylistForSync(activity, playlistUri, true);
1299+
1300+ forceReload();
1301+ if (activity != null && UIUtils.isNetworkConnected(activity)) {
1302+ Intent syncPlaylists = new Intent(SyncService.ACTION_SYNC_PLAYLISTS);
1303+ activity.startService(syncPlaylists);
1304+ }
1305 return true;
1306 }
1307
1308
1309=== modified file 'src/com/ubuntuone/android/music/ui/dialog/InfoAlertDialog.java'
1310--- src/com/ubuntuone/android/music/ui/dialog/InfoAlertDialog.java 2012-11-08 14:14:54 +0000
1311+++ src/com/ubuntuone/android/music/ui/dialog/InfoAlertDialog.java 2012-11-28 17:49:20 +0000
1312@@ -28,6 +28,7 @@
1313 import android.content.DialogInterface.OnClickListener;
1314 import android.os.Bundle;
1315 import android.view.Gravity;
1316+import android.view.ViewGroup.LayoutParams;
1317 import android.widget.TextView;
1318
1319 import com.actionbarsherlock.app.SherlockDialogFragment;
1320@@ -41,7 +42,7 @@
1321 InfoAlertDialog frag = new InfoAlertDialog();
1322 Bundle args = new Bundle();
1323 args.putInt("dialogId", dialogId);
1324- args.putInt("titleId", titleId);
1325+ if (titleId != 0) args.putInt("titleId", titleId);
1326 args.putString("message", message);
1327 frag.setArguments(args);
1328 return frag;
1329@@ -61,11 +62,12 @@
1330 public Dialog onCreateDialog(Bundle savedInstanceState) {
1331 Bundle args = getArguments();
1332 final int dialogId = args.getInt("dialogId");
1333- final int titleId = args.getInt("titleId");
1334 final String message = args.getString("message");
1335
1336 final TextView view = new TextView(getSherlockActivity());
1337+ view.setTextAppearance(getSherlockActivity(), android.R.style.TextAppearance_Large);
1338 view.setGravity(Gravity.CENTER);
1339+ view.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,LayoutParams.WRAP_CONTENT));
1340 view.setText(message);
1341
1342 OnClickListener listener = new OnClickListener() {
1343@@ -79,11 +81,15 @@
1344 }
1345 };
1346
1347- return new AlertDialog.Builder(getActivity())
1348- .setTitle(titleId)
1349+ AlertDialog.Builder builder = new AlertDialog.Builder(getActivity())
1350 .setView(view)
1351- .setPositiveButton(R.string.ok, listener)
1352- .create();
1353+ .setPositiveButton(R.string.ok, listener);
1354+ if (args.containsKey("titleId")) {
1355+ int titleId = args.getInt("titleId");
1356+ builder.setTitle(titleId);
1357+ }
1358+
1359+ return builder.create();
1360 }
1361
1362 public static interface InfoAlertDialogListener {
1363
1364=== modified file 'test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java'
1365--- test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-22 11:17:42 +0000
1366+++ test/src/com/ubuntuone/android/music/provider/MusicProviderInsertTest.java 2012-11-28 17:49:20 +0000
1367@@ -161,7 +161,7 @@
1368
1369 assertNotNull("Inserted song uri is null.", uri);
1370
1371- Cursor cursor = mResolver.query(uri, Songs.DEFAULT_PROJECTION, null, null, null);
1372+ Cursor cursor = mResolver.query(uri, Songs.getDefaultProjection(), null, null, null);
1373 assertEquals("Wrong song row count returned.", 1, cursor.getCount());
1374 assertTrue("Cursor missing rows.", cursor.moveToNext());
1375
1376@@ -218,7 +218,7 @@
1377
1378 Uri uri = Songs.buildSongUri(song.getId());
1379
1380- Cursor cursor = mResolver.query(uri, Songs.DEFAULT_PROJECTION, null, null, null);
1381+ Cursor cursor = mResolver.query(uri, Songs.getDefaultProjection(), null, null, null);
1382 assertEquals("Wrong song row count returned.", 1, cursor.getCount());
1383 assertTrue("Cursor missing rows.", cursor.moveToNext());
1384
1385
1386=== modified file 'test/src/com/ubuntuone/android/music/provider/MusicProviderQueryTest.java'
1387--- test/src/com/ubuntuone/android/music/provider/MusicProviderQueryTest.java 2012-11-08 14:14:54 +0000
1388+++ test/src/com/ubuntuone/android/music/provider/MusicProviderQueryTest.java 2012-11-28 17:49:20 +0000
1389@@ -81,7 +81,7 @@
1390 public void testQueryArtistSongs() {
1391 Uri artistSongsUri = Artists.buildSongsUri(HashUtils.md5("artist1-artist_name"));
1392 Cursor cursor = mResolver.query(artistSongsUri,
1393- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1394+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1395
1396 assertEquals("Wrong artist songs count returned.", 2, cursor.getCount());
1397
1398@@ -141,7 +141,7 @@
1399 Uri albumSongsUri = Albums.buildSongsUri(
1400 HashUtils.md5("album1-album_titleartist1-artist_name"));
1401 Cursor cursor = mResolver.query(albumSongsUri,
1402- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1403+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1404
1405 assertEquals("Wrong album songs count returned.", 2, cursor.getCount());
1406
1407@@ -156,7 +156,7 @@
1408
1409 public void testQuerySongs() {
1410 Cursor cursor = mResolver.query(Songs.CONTENT_URI,
1411- Songs.DEFAULT_PROJECTION, null, null, Songs.DEFAULT_SORT);
1412+ Songs.getDefaultProjection(), null, null, Songs.DEFAULT_SORT);
1413
1414 assertEquals("Wrong song count returned.", MockData.SONGS_COUNT, cursor.getCount());
1415
1416@@ -173,7 +173,7 @@
1417 public void testQuerySongsId() {
1418 Uri songUri = Songs.buildSongUri("song1-song_id");
1419 Cursor cursor = mResolver.query(songUri,
1420- Songs.DEFAULT_PROJECTION, null, null, null);
1421+ Songs.getDefaultProjection(), null, null, null);
1422
1423 assertEquals("Wrong songs count returned.",
1424 1, cursor.getCount());
1425
1426=== modified file 'test/src/com/ubuntuone/android/music/provider/MusicProviderUtilsTest.java'
1427--- test/src/com/ubuntuone/android/music/provider/MusicProviderUtilsTest.java 2012-11-13 13:58:31 +0000
1428+++ test/src/com/ubuntuone/android/music/provider/MusicProviderUtilsTest.java 2012-11-28 17:49:20 +0000
1429@@ -113,7 +113,7 @@
1430 }
1431
1432 public void testGetPlaylistSongCount() {
1433- Uri playlistUri = Playlists.buildPlaylistSongsUri("playlist1-playlist_id");
1434+ Uri playlistUri = Playlists.buildPlaylistUri("playlist1-playlist_id");
1435 int songCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1436 assertEquals("Wrong playlist song count.", 2, songCount);
1437 }
1438@@ -181,7 +181,7 @@
1439 }
1440
1441 public void testEnqueueSongInPlaylist() {
1442- Uri playlistUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1443+ Uri playlistUri = Playlists.buildPlaylistUri("playlist2-playlist_id");
1444 int songCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1445 assertEquals("Wrong song count of playlist.", 1, songCount);
1446
1447@@ -192,10 +192,11 @@
1448 int newSongCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1449 assertEquals("Wrong new song count of playlist.", songCount + 1, newSongCount);
1450
1451+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1452 Cursor cursor = null;
1453 try {
1454 String[] projection = new String[] { Songs.SONG_ID };
1455- cursor = mResolver.query(playlistUri, projection,
1456+ cursor = mResolver.query(playlistSongsUri, projection,
1457 null, null, PlaylistSongs.DEFAULT_SORT);
1458 if (cursor != null && cursor.isBeforeFirst()) {
1459 cursor.moveToLast();
1460@@ -232,7 +233,7 @@
1461 }
1462
1463 public void testEnqueueAlbumInPlaylist() {
1464- Uri playlistUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1465+ Uri playlistUri = Playlists.buildPlaylistUri("playlist2-playlist_id");
1466 int songCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1467 assertEquals("Wrong song count of playlist.", 1, songCount);
1468
1469@@ -244,10 +245,11 @@
1470 int newSongCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1471 assertEquals("Wrong new song count of playlist.", songCount + albumSongCount, newSongCount);
1472
1473+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1474 Cursor cursor = null;
1475 try {
1476 String[] projection = new String[] { Songs.SONG_ID };
1477- cursor = mResolver.query(playlistUri, projection,
1478+ cursor = mResolver.query(playlistSongsUri, projection,
1479 null, null, PlaylistSongs.DEFAULT_SORT);
1480 if (cursor != null && cursor.isBeforeFirst()) {
1481 cursor.moveToFirst();
1482@@ -298,7 +300,7 @@
1483 }
1484
1485 public void testEnqueueArtistInPlaylist() {
1486- Uri playlistUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1487+ Uri playlistUri = Playlists.buildPlaylistUri("playlist2-playlist_id");
1488 int songCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1489 assertEquals("Wrong song count of playlist.", 1, songCount);
1490
1491@@ -311,10 +313,11 @@
1492 int newSongCount = MusicProviderUtils.getPlaylistSongCount(mContext, playlistUri);
1493 assertEquals("Wrong new song count of playlist.", songCount + artistSongCount, newSongCount);
1494
1495+ Uri playlistSongsUri = Playlists.buildPlaylistSongsUri("playlist2-playlist_id");
1496 Cursor cursor = null;
1497 try {
1498 String[] projection = new String[] { Songs.SONG_ID };
1499- cursor = mResolver.query(playlistUri, projection,
1500+ cursor = mResolver.query(playlistSongsUri, projection,
1501 null, null, PlaylistSongs.DEFAULT_SORT);
1502 if (cursor != null && cursor.isBeforeFirst()) {
1503 cursor.moveToFirst();
1504
1505=== modified file 'test/src/com/ubuntuone/android/music/ui/SongsPageTest.java'
1506--- test/src/com/ubuntuone/android/music/ui/SongsPageTest.java 2012-11-08 14:14:54 +0000
1507+++ test/src/com/ubuntuone/android/music/ui/SongsPageTest.java 2012-11-28 17:49:20 +0000
1508@@ -100,6 +100,8 @@
1509 assertNotNull("PlayerActivity was not started",
1510 mInstrumentation.checkMonitorHit(mPlayerActivityMonitor, 1));
1511 activity.finish();
1512+
1513+ mInstrumentation.waitForIdleSync();
1514 }
1515
1516 public void testClearQueueAndPlaySongOnOnListItemClick() {
1517@@ -154,6 +156,8 @@
1518 assertNotNull("PlayerActivity was not started",
1519 mInstrumentation.checkMonitorHit(mPlayerActivityMonitor, 1));
1520 activity.finish();
1521+
1522+ mInstrumentation.waitForIdleSync();
1523 }
1524
1525 public void testOnStarContextItemSelected() {

Subscribers

People subscribed via source and target branches

to all changes: