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;
}
}
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);
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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);
}
/**

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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<Song> 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;
}
}