diff --git a/src/org/kreed/vanilla/LibraryActivity.java b/src/org/kreed/vanilla/LibraryActivity.java index 40810cd8..3b60ba39 100644 --- a/src/org/kreed/vanilla/LibraryActivity.java +++ b/src/org/kreed/vanilla/LibraryActivity.java @@ -435,10 +435,10 @@ public class LibraryActivity all = true; } } - mode = modeForAction[mode]; QueryTask query = buildQueryFromIntent(intent, false, all); - PlaybackService.get(this).addSongs(mode, query, intent.getIntExtra("type", MediaUtils.TYPE_INVALID)); + query.mode = modeForAction[mode]; + PlaybackService.get(this).addSongs(query); mLastActedId = id; @@ -650,7 +650,7 @@ public class LibraryActivity query = MediaUtils.buildFileQuery(intent.getStringExtra("file"), projection); } else if (all || id == LibraryAdapter.HEADER_ID) { query = ((MediaAdapter)mPagerAdapter.mAdapters[type]).buildSongQuery(projection); - query.setExtra(id); + query.data = id; } else { query = MediaUtils.buildQuery(type, id, projection, null); } diff --git a/src/org/kreed/vanilla/MediaAdapter.java b/src/org/kreed/vanilla/MediaAdapter.java index 26b0c969..694b09f4 100644 --- a/src/org/kreed/vanilla/MediaAdapter.java +++ b/src/org/kreed/vanilla/MediaAdapter.java @@ -333,11 +333,12 @@ public class MediaAdapter public QueryTask buildSongQuery(String[] projection) { QueryTask query = buildQuery(projection, true); + query.type = mType; if (mType != MediaUtils.TYPE_SONG) { - query.setUri(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); + query.uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; // Would be better to match the sort order in the adapter. This // is likely to require significantly more work though. - query.setSortOrder(mSongSort); + query.sortOrder = mSongSort; } return query; } diff --git a/src/org/kreed/vanilla/MediaUtils.java b/src/org/kreed/vanilla/MediaUtils.java index 3252fc59..ae1d28b9 100644 --- a/src/org/kreed/vanilla/MediaUtils.java +++ b/src/org/kreed/vanilla/MediaUtils.java @@ -151,7 +151,9 @@ public class MediaUtils { selection.append(select); } - return new QueryTask(media, projection, selection.toString(), null, DEFAULT_SORT); + QueryTask result = new QueryTask(media, projection, selection.toString(), null, DEFAULT_SORT); + result.type = type; + return result; } /** @@ -167,7 +169,10 @@ public class MediaUtils { { Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id); String sort = MediaStore.Audio.Playlists.Members.PLAY_ORDER; - return new QueryTask(uri, projection, selection, null, sort); + QueryTask result = new QueryTask(uri, projection, selection, null, sort); + result.type = TYPE_PLAYLIST; + result.id = id; + return result; } /** @@ -183,7 +188,9 @@ public class MediaUtils { public static QueryTask buildGenreQuery(long id, String[] projection, String selection, String[] selectionArgs, String sort) { Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external", id); - return new QueryTask(uri, projection, selection, selectionArgs, sort); + QueryTask result = new QueryTask(uri, projection, selection, selectionArgs, sort); + result.type = TYPE_GENRE; + return result; } /** @@ -544,6 +551,8 @@ public class MediaUtils { selection.append("*' AND is_music!=0"); Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; - return new QueryTask(media, projection, selection.toString(), null, DEFAULT_SORT); + QueryTask result = new QueryTask(media, projection, selection.toString(), null, DEFAULT_SORT); + result.type = TYPE_FILE; + return result; } } diff --git a/src/org/kreed/vanilla/PlaybackService.java b/src/org/kreed/vanilla/PlaybackService.java index baa022f3..daaabd6a 100644 --- a/src/org/kreed/vanilla/PlaybackService.java +++ b/src/org/kreed/vanilla/PlaybackService.java @@ -89,7 +89,7 @@ public final class PlaybackService extends Service /** * State file version that indicates data order. */ - private static final int STATE_VERSION = 5; + private static final int STATE_VERSION = 6; private static final int NOTIFICATION_ID = 2; @@ -1199,7 +1199,7 @@ public final class PlaybackService extends Service processSong((Song)message.obj); break; case QUERY: - runQuery(message.arg1, (QueryTask)message.obj, message.arg2); + runQuery((QueryTask)message.obj); break; case IDLE_TIMEOUT: if ((mState & FLAG_PLAYING) != 0) { @@ -1365,25 +1365,15 @@ public final class PlaybackService extends Service * Run the query and add the results to the timeline. Should be called in the * worker thread. * - * @param mode How to add songs. Passed to - * {@link SongTimeline#addSongs(int, android.database.Cursor, int, long)} * @param query The query to run. - * @param jumpTo Passed to - * {@link SongTimeline#addSongs(int, android.database.Cursor, int, long)} */ - public void runQuery(int mode, QueryTask query, int jumpTo) + public void runQuery(QueryTask query) { - Cursor cursor = query.runQuery(getContentResolver()); - if (cursor == null) { - return; - } - - int count = mTimeline.addSongs(mode, cursor, jumpTo, query.getExtra()); - cursor.close(); + int count = mTimeline.addSongs(this, query); int text; - switch (mode) { + switch (query.mode) { case SongTimeline.MODE_PLAY: case SongTimeline.MODE_PLAY_POS_FIRST: case SongTimeline.MODE_PLAY_ID_FIRST: @@ -1398,7 +1388,7 @@ public final class PlaybackService extends Service text = R.plurals.enqueued; break; default: - throw new IllegalArgumentException("Invalid add mode: " + mode); + throw new IllegalArgumentException("Invalid add mode: " + query.mode); } Toast.makeText(this, getResources().getQuantityString(text, count, count), Toast.LENGTH_SHORT).show(); @@ -1407,15 +1397,11 @@ public final class PlaybackService extends Service /** * Run the query in the background and add the results to the timeline. * - * @param mode One of SongTimeline.MODE_*. Tells whether to play the songs - * immediately or enqueue them for later. * @param query The query. - * @param jumpTo Passed to - * {@link SongTimeline#addSongs(int, android.database.Cursor, int, long)} */ - public void addSongs(int mode, QueryTask query, int jumpTo) + public void addSongs(QueryTask query) { - mHandler.sendMessage(mHandler.obtainMessage(QUERY, mode, jumpTo, query)); + mHandler.sendMessage(mHandler.obtainMessage(QUERY, query)); } /** @@ -1450,7 +1436,9 @@ public final class PlaybackService extends Service } String selection = "_id!=" + current.id; - addSongs(SongTimeline.MODE_PLAY_NEXT, MediaUtils.buildQuery(type, id, Song.FILLED_PROJECTION, selection), 0); + QueryTask query = MediaUtils.buildQuery(type, id, Song.FILLED_PROJECTION, selection); + query.mode = SongTimeline.MODE_PLAY_NEXT; + addSongs(query); } /** diff --git a/src/org/kreed/vanilla/PlaylistActivity.java b/src/org/kreed/vanilla/PlaylistActivity.java index ca81eb8f..5b25b10c 100644 --- a/src/org/kreed/vanilla/PlaylistActivity.java +++ b/src/org/kreed/vanilla/PlaylistActivity.java @@ -232,13 +232,16 @@ public class PlaylistActivity extends Activity case LibraryActivity.ACTION_PLAY: case LibraryActivity.ACTION_ENQUEUE: { QueryTask query = MediaUtils.buildMediaQuery(MediaUtils.TYPE_SONG, audioId, Song.FILLED_PROJECTION, null); - PlaybackService.get(this).addSongs(MODE_FOR_ACTION[action], query, 0); + query.mode = MODE_FOR_ACTION[action]; + PlaybackService.get(this).addSongs(query); break; } case LibraryActivity.ACTION_PLAY_ALL: case LibraryActivity.ACTION_ENQUEUE_ALL: { QueryTask query = MediaUtils.buildPlaylistQuery(mPlaylistId, Song.FILLED_PLAYLIST_PROJECTION, null); - PlaybackService.get(this).addSongs(MODE_FOR_ACTION[action], query, position - mListView.getHeaderViewsCount()); + query.mode = MODE_FOR_ACTION[action]; + query.data = position - mListView.getHeaderViewsCount(); + PlaybackService.get(this).addSongs(query); break; } } diff --git a/src/org/kreed/vanilla/QueryTask.java b/src/org/kreed/vanilla/QueryTask.java index e2a9bf02..e975bdd2 100644 --- a/src/org/kreed/vanilla/QueryTask.java +++ b/src/org/kreed/vanilla/QueryTask.java @@ -30,12 +30,33 @@ import android.net.Uri; * Represents a pending query. */ public class QueryTask { - private Uri mUri; - private final String[] mProjection; - private final String mSelection; - private final String[] mSelectionArgs; - private String mSortOrder; - private long mExtra; + public Uri uri; + public final String[] projection; + public final String selection; + public final String[] selectionArgs; + public String sortOrder; + + /** + * Used for {@link SongTimeline#addSongs(android.content.Context, QueryTask)}. + * One of SongTimeline.MODE_*. + */ + public int mode; + + /** + * Id of the group being queried. + */ + public long id; + + /** + * Type of the group being query. One of MediaUtils.TYPE_*. + */ + public int type; + + /** + * Data. Required value depends on value of mode. See individual mode + * documentation for details. + */ + public long data; /** * Create the tasks. All arguments are passed directly to @@ -43,52 +64,11 @@ public class QueryTask { */ public QueryTask(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - mUri = uri; - mProjection = projection; - mSelection = selection; - mSelectionArgs = selectionArgs; - mSortOrder = sortOrder; - } - - /** - * Modify the uri of the pending query. - * - * @param uri The new uri. - */ - public void setUri(Uri uri) - { - mUri = uri; - } - - /** - * Modify the sort order of the pending query. - * - * @param sortOrder The new sort order. - */ - public void setSortOrder(String sortOrder) - { - mSortOrder = sortOrder; - } - - /** - * Store some extra data with this query. This data is not used at all by - * when running the query. - * - * @param extra The extra data - */ - public void setExtra(long extra) - { - mExtra = extra; - } - - /** - * Retrieve the extra data stored by {@link QueryTask#setExtra(long)} - * - * @return The extra data - */ - public long getExtra() - { - return mExtra; + this.uri = uri; + this.projection = projection; + this.selection = selection; + this.selectionArgs = selectionArgs; + this.sortOrder = sortOrder; } /** @@ -98,6 +78,6 @@ public class QueryTask { */ public Cursor runQuery(ContentResolver resolver) { - return resolver.query(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder); + return resolver.query(uri, projection, selection, selectionArgs, sortOrder); } } diff --git a/src/org/kreed/vanilla/SongTimeline.java b/src/org/kreed/vanilla/SongTimeline.java index 11cc5f21..488243e2 100644 --- a/src/org/kreed/vanilla/SongTimeline.java +++ b/src/org/kreed/vanilla/SongTimeline.java @@ -88,19 +88,19 @@ public final class SongTimeline { /** * Clear the timeline and use only the provided songs. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_PLAY = 0; /** * Clear the queue and add the songs after the current song. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_PLAY_NEXT = 1; /** * Add the songs at the end of the timeline, clearing random songs. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_ENQUEUE = 2; /** @@ -108,9 +108,9 @@ public final class SongTimeline { * removing the songs before the given position in the query and appending * them to the end of the queue. * - * Pass the position in the integer argument. + * Pass the position in QueryTask.data. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_PLAY_POS_FIRST = 3; /** @@ -119,11 +119,9 @@ public final class SongTimeline { * them to the end of the queue. If there are multiple songs with * the given id, picks the first song with that id. * - * Pass the id in the long argument and the type of the id (one of - * MediaUtils.TYPE_ARTIST, TYPE_ALBUM or TYPE_SONG) in the integer - * argument. + * Pass the id in QueryTask.data. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_PLAY_ID_FIRST = 4; /** @@ -132,11 +130,9 @@ public final class SongTimeline { * them to the end of the queue. If there are multiple songs with * the given id, picks the first song with that id. * - * Pass the id in the long argument and the type of the id (one of - * MediaUtils.TYPE_ARTIST, TYPE_ALBUM or TYPE_SONG) in the integer - * argument. + * Pass the id in QueryTask.data. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_ENQUEUE_ID_FIRST = 5; /** @@ -144,9 +140,9 @@ public final class SongTimeline { * removing the songs before the given position in the query and appending * them to the end of the queue. * - * Pass the position in the integer argument. + * Pass the position in QueryTask.data. * - * @see SongTimeline#addSongs(int, android.database.Cursor, int, long) + * @see SongTimeline#addSongs(Context, QueryTask) */ public static final int MODE_ENQUEUE_POS_FIRST = 6; @@ -303,8 +299,11 @@ public final class SongTimeline { StringBuilder selection = new StringBuilder("_ID IN ("); for (int i = 0; i != n; ++i) { long id = in.readLong(); + if (id == -1) + continue; + // Add the index to the flags so we can sort - int flags = (in.readInt() & ~(~0 << Song.FLAG_COUNT)) | (i << Song.FLAG_COUNT); + int flags = in.readInt() & ~(~0 << Song.FLAG_COUNT) | i << Song.FLAG_COUNT; songs.add(new Song(id, flags)); if (i != 0) @@ -375,7 +374,6 @@ public final class SongTimeline { Song song = songs.get(i); if (song == null) { out.writeLong(-1); - out.writeInt(0); } else { out.writeLong(song.id); out.writeInt(song.flags); @@ -580,23 +578,29 @@ public final class SongTimeline { } /** - * Add the songs from the given cursor to the song timeline. + * Run the given query and add the results to the song timeline. * - * @param mode How to add the songs. One of SongTimeline.MODE_*. - * @param cursor The cursor to fill from. - * @param i The integer argument. See individual mode documentation for - * usage. - * @param l The long argument. See individual mode documentation for - * usage. + * @param context A context to use. + * @param query The query to be run. The mode variable must be initialized + * to one of SongTimeline.MODE_*. The type and data variables may also need + * to be initialized depending on the given mode. * @return The number of songs that were added. */ - public int addSongs(int mode, Cursor cursor, int i, long l) + public int addSongs(Context context, QueryTask query) { - if (cursor == null) + Cursor cursor = query.runQuery(context.getContentResolver()); + if (cursor == null) { return 0; + } + int count = cursor.getCount(); - if (count == 0) + if (count == 0) { return 0; + } + + int mode = query.mode; + int type = query.type; + long data = query.data; ArrayList timeline = mSongs; synchronized (this) { @@ -636,11 +640,11 @@ public final class SongTimeline { timeline.add(song); if (jumpSong == null) { - if ((mode == MODE_PLAY_POS_FIRST || mode == MODE_ENQUEUE_POS_FIRST) && j == i) { + if ((mode == MODE_PLAY_POS_FIRST || mode == MODE_ENQUEUE_POS_FIRST) && j == data) { jumpSong = song; } else if (mode == MODE_PLAY_ID_FIRST || mode == MODE_ENQUEUE_ID_FIRST) { long id; - switch (i) { + switch (type) { case MediaUtils.TYPE_ARTIST: id = song.artistId; break; @@ -651,9 +655,9 @@ public final class SongTimeline { id = song.id; break; default: - throw new IllegalArgumentException("Unsupported id type: " + i); + throw new IllegalArgumentException("Unsupported id type: " + type); } - if (id == l) + if (id == data) jumpSong = song; } }