Refactor SongTimeline.addSongs() so it receives arguments from QueryTask

This commit is contained in:
Christopher Eby 2012-01-22 14:01:25 -06:00
parent 3774d386e3
commit 64d716571f
7 changed files with 103 additions and 118 deletions

View File

@ -435,10 +435,10 @@ public class LibraryActivity
all = true; all = true;
} }
} }
mode = modeForAction[mode];
QueryTask query = buildQueryFromIntent(intent, false, all); 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; mLastActedId = id;
@ -650,7 +650,7 @@ public class LibraryActivity
query = MediaUtils.buildFileQuery(intent.getStringExtra("file"), projection); query = MediaUtils.buildFileQuery(intent.getStringExtra("file"), projection);
} else if (all || id == LibraryAdapter.HEADER_ID) { } else if (all || id == LibraryAdapter.HEADER_ID) {
query = ((MediaAdapter)mPagerAdapter.mAdapters[type]).buildSongQuery(projection); query = ((MediaAdapter)mPagerAdapter.mAdapters[type]).buildSongQuery(projection);
query.setExtra(id); query.data = id;
} else { } else {
query = MediaUtils.buildQuery(type, id, projection, null); query = MediaUtils.buildQuery(type, id, projection, null);
} }

View File

@ -333,11 +333,12 @@ public class MediaAdapter
public QueryTask buildSongQuery(String[] projection) public QueryTask buildSongQuery(String[] projection)
{ {
QueryTask query = buildQuery(projection, true); QueryTask query = buildQuery(projection, true);
query.type = mType;
if (mType != MediaUtils.TYPE_SONG) { 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 // Would be better to match the sort order in the adapter. This
// is likely to require significantly more work though. // is likely to require significantly more work though.
query.setSortOrder(mSongSort); query.sortOrder = mSongSort;
} }
return query; return query;
} }

View File

@ -151,7 +151,9 @@ public class MediaUtils {
selection.append(select); 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); Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", id);
String sort = MediaStore.Audio.Playlists.Members.PLAY_ORDER; 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) public static QueryTask buildGenreQuery(long id, String[] projection, String selection, String[] selectionArgs, String sort)
{ {
Uri uri = MediaStore.Audio.Genres.Members.getContentUri("external", id); 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"); selection.append("*' AND is_music!=0");
Uri media = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 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;
} }
} }

View File

@ -89,7 +89,7 @@ public final class PlaybackService extends Service
/** /**
* State file version that indicates data order. * 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; private static final int NOTIFICATION_ID = 2;
@ -1199,7 +1199,7 @@ public final class PlaybackService extends Service
processSong((Song)message.obj); processSong((Song)message.obj);
break; break;
case QUERY: case QUERY:
runQuery(message.arg1, (QueryTask)message.obj, message.arg2); runQuery((QueryTask)message.obj);
break; break;
case IDLE_TIMEOUT: case IDLE_TIMEOUT:
if ((mState & FLAG_PLAYING) != 0) { 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 * Run the query and add the results to the timeline. Should be called in the
* worker thread. * 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 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()); int count = mTimeline.addSongs(this, query);
if (cursor == null) {
return;
}
int count = mTimeline.addSongs(mode, cursor, jumpTo, query.getExtra());
cursor.close();
int text; int text;
switch (mode) { switch (query.mode) {
case SongTimeline.MODE_PLAY: case SongTimeline.MODE_PLAY:
case SongTimeline.MODE_PLAY_POS_FIRST: case SongTimeline.MODE_PLAY_POS_FIRST:
case SongTimeline.MODE_PLAY_ID_FIRST: case SongTimeline.MODE_PLAY_ID_FIRST:
@ -1398,7 +1388,7 @@ public final class PlaybackService extends Service
text = R.plurals.enqueued; text = R.plurals.enqueued;
break; break;
default: 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(); 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. * 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 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; 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);
} }
/** /**

View File

@ -232,13 +232,16 @@ public class PlaylistActivity extends Activity
case LibraryActivity.ACTION_PLAY: case LibraryActivity.ACTION_PLAY:
case LibraryActivity.ACTION_ENQUEUE: { case LibraryActivity.ACTION_ENQUEUE: {
QueryTask query = MediaUtils.buildMediaQuery(MediaUtils.TYPE_SONG, audioId, Song.FILLED_PROJECTION, null); 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; break;
} }
case LibraryActivity.ACTION_PLAY_ALL: case LibraryActivity.ACTION_PLAY_ALL:
case LibraryActivity.ACTION_ENQUEUE_ALL: { case LibraryActivity.ACTION_ENQUEUE_ALL: {
QueryTask query = MediaUtils.buildPlaylistQuery(mPlaylistId, Song.FILLED_PLAYLIST_PROJECTION, null); 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; break;
} }
} }

View File

@ -30,12 +30,33 @@ import android.net.Uri;
* Represents a pending query. * Represents a pending query.
*/ */
public class QueryTask { public class QueryTask {
private Uri mUri; public Uri uri;
private final String[] mProjection; public final String[] projection;
private final String mSelection; public final String selection;
private final String[] mSelectionArgs; public final String[] selectionArgs;
private String mSortOrder; public String sortOrder;
private long mExtra;
/**
* 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 * 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) public QueryTask(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
{ {
mUri = uri; this.uri = uri;
mProjection = projection; this.projection = projection;
mSelection = selection; this.selection = selection;
mSelectionArgs = selectionArgs; this.selectionArgs = selectionArgs;
mSortOrder = sortOrder; this.sortOrder = 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;
} }
/** /**
@ -98,6 +78,6 @@ public class QueryTask {
*/ */
public Cursor runQuery(ContentResolver resolver) public Cursor runQuery(ContentResolver resolver)
{ {
return resolver.query(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder); return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
} }
} }

View File

@ -88,19 +88,19 @@ public final class SongTimeline {
/** /**
* Clear the timeline and use only the provided songs. * 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; public static final int MODE_PLAY = 0;
/** /**
* Clear the queue and add the songs after the current song. * 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; public static final int MODE_PLAY_NEXT = 1;
/** /**
* Add the songs at the end of the timeline, clearing random songs. * 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; 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 * removing the songs before the given position in the query and appending
* them to the end of the queue. * 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; 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 * them to the end of the queue. If there are multiple songs with
* the given id, picks the first song with that id. * 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 * Pass the id in QueryTask.data.
* MediaUtils.TYPE_ARTIST, TYPE_ALBUM or TYPE_SONG) in the integer
* argument.
* *
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long) * @see SongTimeline#addSongs(Context, QueryTask)
*/ */
public static final int MODE_PLAY_ID_FIRST = 4; 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 * them to the end of the queue. If there are multiple songs with
* the given id, picks the first song with that id. * 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 * Pass the id in QueryTask.data.
* MediaUtils.TYPE_ARTIST, TYPE_ALBUM or TYPE_SONG) in the integer
* argument.
* *
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long) * @see SongTimeline#addSongs(Context, QueryTask)
*/ */
public static final int MODE_ENQUEUE_ID_FIRST = 5; 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 * removing the songs before the given position in the query and appending
* them to the end of the queue. * 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; public static final int MODE_ENQUEUE_POS_FIRST = 6;
@ -303,8 +299,11 @@ public final class SongTimeline {
StringBuilder selection = new StringBuilder("_ID IN ("); StringBuilder selection = new StringBuilder("_ID IN (");
for (int i = 0; i != n; ++i) { for (int i = 0; i != n; ++i) {
long id = in.readLong(); long id = in.readLong();
if (id == -1)
continue;
// Add the index to the flags so we can sort // 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)); songs.add(new Song(id, flags));
if (i != 0) if (i != 0)
@ -375,7 +374,6 @@ public final class SongTimeline {
Song song = songs.get(i); Song song = songs.get(i);
if (song == null) { if (song == null) {
out.writeLong(-1); out.writeLong(-1);
out.writeInt(0);
} else { } else {
out.writeLong(song.id); out.writeLong(song.id);
out.writeInt(song.flags); 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 context A context to use.
* @param cursor The cursor to fill from. * @param query The query to be run. The mode variable must be initialized
* @param i The integer argument. See individual mode documentation for * to one of SongTimeline.MODE_*. The type and data variables may also need
* usage. * to be initialized depending on the given mode.
* @param l The long argument. See individual mode documentation for
* usage.
* @return The number of songs that were added. * @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; return 0;
}
int count = cursor.getCount(); int count = cursor.getCount();
if (count == 0) if (count == 0) {
return 0; return 0;
}
int mode = query.mode;
int type = query.type;
long data = query.data;
ArrayList<Song> timeline = mSongs; ArrayList<Song> timeline = mSongs;
synchronized (this) { synchronized (this) {
@ -636,11 +640,11 @@ public final class SongTimeline {
timeline.add(song); timeline.add(song);
if (jumpSong == null) { 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; jumpSong = song;
} else if (mode == MODE_PLAY_ID_FIRST || mode == MODE_ENQUEUE_ID_FIRST) { } else if (mode == MODE_PLAY_ID_FIRST || mode == MODE_ENQUEUE_ID_FIRST) {
long id; long id;
switch (i) { switch (type) {
case MediaUtils.TYPE_ARTIST: case MediaUtils.TYPE_ARTIST:
id = song.artistId; id = song.artistId;
break; break;
@ -651,9 +655,9 @@ public final class SongTimeline {
id = song.id; id = song.id;
break; break;
default: default:
throw new IllegalArgumentException("Unsupported id type: " + i); throw new IllegalArgumentException("Unsupported id type: " + type);
} }
if (id == l) if (id == data)
jumpSong = song; jumpSong = song;
} }
} }