Add play all and enqueue all library actions
Similar to the play all and enqueue all headers, but plays selected row first. This is similar to the default behavior of most music player's libraries
This commit is contained in:
parent
bc1f587730
commit
d43dcc14ae
@ -42,6 +42,7 @@ THE SOFTWARE.
|
||||
<item>1</item>
|
||||
<item>2</item>
|
||||
<item>3</item>
|
||||
<item>4</item>
|
||||
</string-array>
|
||||
<string-array name="swipe_action_values">
|
||||
<!-- This must match the order of swipe_action_entries exactly and
|
||||
@ -78,6 +79,8 @@ THE SOFTWARE.
|
||||
<item>@string/play</item>
|
||||
<item>@string/enqueue</item>
|
||||
<item>@string/last_used_action</item>
|
||||
<item>@string/play_all</item>
|
||||
<item>@string/enqueue_all</item>
|
||||
</string-array>
|
||||
<string-array name="notification_mode_entries">
|
||||
<item>@string/never_show</item>
|
||||
|
@ -68,8 +68,11 @@ public class LibraryActivity
|
||||
private static final int ACTION_PLAY = 0;
|
||||
private static final int ACTION_ENQUEUE = 1;
|
||||
private static final int ACTION_LAST_USED = 2;
|
||||
private static final int ACTION_PLAY_ALL = 3;
|
||||
private static final int ACTION_ENQUEUE_ALL = 4;
|
||||
private static final int[] modeForAction =
|
||||
{ SongTimeline.MODE_PLAY, SongTimeline.MODE_ENQUEUE };
|
||||
{ SongTimeline.MODE_PLAY, SongTimeline.MODE_ENQUEUE, -1,
|
||||
SongTimeline.MODE_PLAY_ID_FIRST, SongTimeline.MODE_ENQUEUE_ID_FIRST };
|
||||
|
||||
private TabHost mTabHost;
|
||||
|
||||
@ -248,7 +251,7 @@ public class LibraryActivity
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
|
||||
int res = action == ACTION_ENQUEUE ? R.string.enqueue_all : R.string.play_all;
|
||||
int res = action == ACTION_ENQUEUE || action == ACTION_ENQUEUE_ALL ? R.string.enqueue_all : R.string.play_all;
|
||||
String text = getString(res);
|
||||
mArtistAdapter.setHeaderText(text);
|
||||
mAlbumAdapter.setHeaderText(text);
|
||||
@ -267,11 +270,28 @@ public class LibraryActivity
|
||||
if (action == ACTION_LAST_USED)
|
||||
action = mLastAction;
|
||||
|
||||
int mode = modeForAction[action];
|
||||
QueryTask query = buildQueryFromIntent(intent, false);
|
||||
PlaybackService.get(this).addSongs(mode, query, 0);
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
|
||||
mLastActedId = intent.getLongExtra("id", -1);
|
||||
boolean all = false;
|
||||
int mode = action;
|
||||
if (action == ACTION_PLAY_ALL || action == ACTION_ENQUEUE_ALL) {
|
||||
MediaAdapter adapter = mCurrentAdapter;
|
||||
boolean notPlayAllAdapter = (adapter != mSongAdapter && adapter != mAlbumAdapter
|
||||
&& adapter != mArtistAdapter) || id == MediaView.HEADER_ID;
|
||||
if (mode == ACTION_ENQUEUE_ALL && notPlayAllAdapter) {
|
||||
mode = ACTION_ENQUEUE;
|
||||
} else if (mode == ACTION_PLAY_ALL && notPlayAllAdapter) {
|
||||
mode = ACTION_PLAY;
|
||||
} else {
|
||||
all = true;
|
||||
}
|
||||
}
|
||||
mode = modeForAction[mode];
|
||||
|
||||
QueryTask query = buildQueryFromIntent(intent, false, all);
|
||||
PlaybackService.get(this).addSongs(mode, query, intent.getIntExtra("type", -1));
|
||||
|
||||
mLastActedId = id;
|
||||
|
||||
if (mDefaultAction == ACTION_LAST_USED && mLastAction != action) {
|
||||
mLastAction = action;
|
||||
@ -333,6 +353,7 @@ public class LibraryActivity
|
||||
return tab;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> list, View view, int pos, long id)
|
||||
{
|
||||
MediaView mediaView = (MediaView)view;
|
||||
@ -349,14 +370,17 @@ public class LibraryActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence text, int start, int before, int count)
|
||||
{
|
||||
String filter = text.toString();
|
||||
@ -463,8 +487,10 @@ public class LibraryActivity
|
||||
* @param intent An intent created with
|
||||
* {@link LibraryActivity#createClickIntent(MediaAdapter,MediaView)}.
|
||||
* @param empty If true, use the empty projection (only query id).
|
||||
* @param all If true query all songs in the adapter; otherwise query based
|
||||
* on the row selected.
|
||||
*/
|
||||
private QueryTask buildQueryFromIntent(Intent intent, boolean empty)
|
||||
private QueryTask buildQueryFromIntent(Intent intent, boolean empty, boolean all)
|
||||
{
|
||||
int type = intent.getIntExtra("type", 1);
|
||||
|
||||
@ -476,10 +502,12 @@ public class LibraryActivity
|
||||
|
||||
long id = intent.getLongExtra("id", -1);
|
||||
QueryTask query;
|
||||
if (id == MediaView.HEADER_ID)
|
||||
if (all || id == MediaView.HEADER_ID) {
|
||||
query = mAdapters[type - 1].buildSongQuery(projection);
|
||||
else
|
||||
query.setExtra(id);
|
||||
} else {
|
||||
query = MediaUtils.buildQuery(type, id, projection, null);
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
@ -493,6 +521,8 @@ public class LibraryActivity
|
||||
private static final int MENU_EDIT = 6;
|
||||
private static final int MENU_RENAME_PLAYLIST = 7;
|
||||
private static final int MENU_SELECT_PLAYLIST = 8;
|
||||
private static final int MENU_PLAY_ALL = 9;
|
||||
private static final int MENU_ENQUEUE_ALL = 10;
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View listView, ContextMenu.ContextMenuInfo absInfo)
|
||||
@ -505,6 +535,7 @@ public class LibraryActivity
|
||||
Intent intent = createClickIntent(adapter, view);
|
||||
|
||||
boolean isHeader = view.getMediaId() == MediaView.HEADER_ID;
|
||||
boolean isAllAdapter = adapter == mArtistAdapter || adapter == mAlbumAdapter || adapter == mSongAdapter;
|
||||
|
||||
if (isHeader)
|
||||
menu.setHeaderTitle(getString(R.string.all_songs));
|
||||
@ -512,7 +543,11 @@ public class LibraryActivity
|
||||
menu.setHeaderTitle(view.getTitle());
|
||||
|
||||
menu.add(0, MENU_PLAY, 0, R.string.play).setIntent(intent);
|
||||
if (isAllAdapter)
|
||||
menu.add(0, MENU_PLAY_ALL, 0, R.string.play_all).setIntent(intent);
|
||||
menu.add(0, MENU_ENQUEUE, 0, R.string.enqueue).setIntent(intent);
|
||||
if (isAllAdapter)
|
||||
menu.add(0, MENU_ENQUEUE_ALL, 0, R.string.enqueue_all).setIntent(intent);
|
||||
if (adapter == mPlaylistAdapter) {
|
||||
menu.add(0, MENU_RENAME_PLAYLIST, 0, R.string.rename).setIntent(intent);
|
||||
menu.add(0, MENU_EDIT, 0, R.string.edit).setIntent(intent);
|
||||
@ -534,7 +569,7 @@ public class LibraryActivity
|
||||
*/
|
||||
private void addToPlaylist(long playlistId, Intent intent)
|
||||
{
|
||||
QueryTask query = buildQueryFromIntent(intent, true);
|
||||
QueryTask query = buildQueryFromIntent(intent, true, false);
|
||||
int count = Playlist.addToPlaylist(getContentResolver(), playlistId, query);
|
||||
|
||||
String message = getResources().getQuantityString(R.plurals.added_to_playlist, count, count, intent.getStringExtra("playlistName"));
|
||||
@ -590,6 +625,12 @@ public class LibraryActivity
|
||||
case MENU_PLAY:
|
||||
pickSongs(intent, ACTION_PLAY);
|
||||
break;
|
||||
case MENU_PLAY_ALL:
|
||||
pickSongs(intent, ACTION_PLAY_ALL);
|
||||
break;
|
||||
case MENU_ENQUEUE_ALL:
|
||||
pickSongs(intent, ACTION_ENQUEUE_ALL);
|
||||
break;
|
||||
case MENU_NEW_PLAYLIST: {
|
||||
NewPlaylistDialog dialog = new NewPlaylistDialog(this, null, R.string.create, intent);
|
||||
dialog.setDismissMessage(mHandler.obtainMessage(MSG_NEW_PLAYLIST, dialog));
|
||||
|
@ -1127,33 +1127,34 @@ public final class PlaybackService extends Service implements Handler.Callback,
|
||||
* worker thread.
|
||||
*
|
||||
* @param mode How to add songs. Passed to
|
||||
* {@link SongTimeline#addSongs(int, android.database.Cursor, int)}
|
||||
* {@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)}
|
||||
* {@link SongTimeline#addSongs(int, android.database.Cursor, int, long)}
|
||||
*/
|
||||
public void runQuery(int mode, QueryTask query, int jumpTo)
|
||||
{
|
||||
int count = mTimeline.addSongs(mode, query.runQuery(getContentResolver()), jumpTo);
|
||||
int count = mTimeline.addSongs(mode, query.runQuery(getContentResolver()), jumpTo, query.getExtra());
|
||||
|
||||
int text;
|
||||
|
||||
switch (mode) {
|
||||
case SongTimeline.MODE_PLAY:
|
||||
case SongTimeline.MODE_PLAY_JUMP_TO:
|
||||
case SongTimeline.MODE_PLAY_POS_FIRST:
|
||||
case SongTimeline.MODE_PLAY_ID_FIRST:
|
||||
text = R.plurals.playing;
|
||||
if (count != 0 && (mState & FLAG_PLAYING) == 0)
|
||||
setFlag(FLAG_PLAYING);
|
||||
break;
|
||||
case SongTimeline.MODE_PLAY_NEXT:
|
||||
case SongTimeline.MODE_ENQUEUE:
|
||||
case SongTimeline.MODE_ENQUEUE_ID_FIRST:
|
||||
text = R.plurals.enqueued;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
throw new IllegalArgumentException("Invalid add mode: " + mode);
|
||||
}
|
||||
|
||||
if ((mode == SongTimeline.MODE_PLAY || mode == SongTimeline.MODE_PLAY_JUMP_TO) && count != 0 && (mState & FLAG_PLAYING) == 0)
|
||||
setFlag(FLAG_PLAYING);
|
||||
|
||||
Toast.makeText(this, getResources().getQuantityString(text, count, count), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@ -1164,7 +1165,7 @@ public final class PlaybackService extends Service implements Handler.Callback,
|
||||
* immediately or enqueue them for later.
|
||||
* @param query The query.
|
||||
* @param jumpTo Passed to
|
||||
* {@link SongTimeline#addSongs(int, android.database.Cursor, int)}
|
||||
* {@link SongTimeline#addSongs(int, android.database.Cursor, int, long)}
|
||||
*/
|
||||
public void addSongs(int mode, QueryTask query, int jumpTo)
|
||||
{
|
||||
|
@ -139,7 +139,7 @@ public class PlaylistActivity extends Activity
|
||||
mAdapter.remove(id);
|
||||
} else if (!mEditing) {
|
||||
QueryTask query = MediaUtils.buildPlaylistQuery(mPlaylistId, Song.FILLED_PLAYLIST_PROJECTION, null);
|
||||
PlaybackService.get(this).addSongs(SongTimeline.MODE_PLAY_JUMP_TO, query, position - mListView.getHeaderViewsCount());
|
||||
PlaybackService.get(this).addSongs(SongTimeline.MODE_PLAY_POS_FIRST, query, position - mListView.getHeaderViewsCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ public class QueryTask {
|
||||
private final String mSelection;
|
||||
private final String[] mSelectionArgs;
|
||||
private String mSortOrder;
|
||||
private long mExtra;
|
||||
|
||||
/**
|
||||
* Create the tasks. All arguments are passed directly to
|
||||
@ -69,6 +70,27 @@ public class QueryTask {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the query. Should be called on a background thread.
|
||||
*
|
||||
|
@ -74,28 +74,57 @@ public final class SongTimeline {
|
||||
/**
|
||||
* Clear the timeline and use only the provided songs.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int,Cursor,int)
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_PLAY = 0;
|
||||
/**
|
||||
* Clear the queue and add the songs after the current song.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int,Cursor,int)
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_PLAY_NEXT = 1;
|
||||
/**
|
||||
* Add the songs at the end of the timeline, clearing random songs.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int,Cursor,int)
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_ENQUEUE = 2;
|
||||
/**
|
||||
* Like play mode, but make the current position point to the song at
|
||||
* the given position.
|
||||
* Like play mode, but make the song at the given position play first by
|
||||
* removing the songs before the given position in the query and appending
|
||||
* them to the end of the queue.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int,Cursor,int)
|
||||
* Pass the position in the integer argument.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_PLAY_JUMP_TO = 3;
|
||||
public static final int MODE_PLAY_POS_FIRST = 3;
|
||||
/**
|
||||
* Like play mode, but make the song with the given id play first by
|
||||
* removing the songs before the song in the query and appending
|
||||
* 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.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_PLAY_ID_FIRST = 4;
|
||||
/**
|
||||
* Like enqueue mode, but make the song with the given id play first by
|
||||
* removing the songs before the song in the query and appending
|
||||
* 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.
|
||||
*
|
||||
* @see SongTimeline#addSongs(int, android.database.Cursor, int, long)
|
||||
*/
|
||||
public static final int MODE_ENQUEUE_ID_FIRST = 5;
|
||||
|
||||
/**
|
||||
* Disable shuffle.
|
||||
@ -486,10 +515,13 @@ public final class SongTimeline {
|
||||
*
|
||||
* @param mode How to add the songs. One of SongTimeline.MODE_*.
|
||||
* @param cursor The cursor to fill from.
|
||||
* @param jumpTo The position to jump to for MODE_PLAY_JUMP_TO.
|
||||
* @param i The integer argument. See individual mode documentation for
|
||||
* usage.
|
||||
* @param l The long argument. See individual mode documentation for
|
||||
* usage.
|
||||
* @return The number of songs that were added.
|
||||
*/
|
||||
public int addSongs(int mode, Cursor cursor, int jumpTo)
|
||||
public int addSongs(int mode, Cursor cursor, int i, long l)
|
||||
{
|
||||
if (cursor == null)
|
||||
return 0;
|
||||
@ -502,11 +534,12 @@ public final class SongTimeline {
|
||||
saveActiveSongs();
|
||||
|
||||
switch (mode) {
|
||||
case MODE_ENQUEUE: {
|
||||
int i = timeline.size();
|
||||
while (--i > mCurrentPos) {
|
||||
if (timeline.get(i).isRandom())
|
||||
timeline.remove(i);
|
||||
case MODE_ENQUEUE:
|
||||
case MODE_ENQUEUE_ID_FIRST: {
|
||||
int j = timeline.size();
|
||||
while (--j > mCurrentPos) {
|
||||
if (timeline.get(j).isRandom())
|
||||
timeline.remove(j);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -514,7 +547,8 @@ public final class SongTimeline {
|
||||
timeline.subList(mCurrentPos + 1, timeline.size()).clear();
|
||||
break;
|
||||
case MODE_PLAY:
|
||||
case MODE_PLAY_JUMP_TO:
|
||||
case MODE_PLAY_POS_FIRST:
|
||||
case MODE_PLAY_ID_FIRST:
|
||||
timeline.clear();
|
||||
mCurrentPos = 0;
|
||||
break;
|
||||
@ -530,15 +564,42 @@ public final class SongTimeline {
|
||||
Song song = new Song(-1);
|
||||
song.populate(cursor);
|
||||
timeline.add(song);
|
||||
if (j == jumpTo)
|
||||
jumpSong = song;
|
||||
|
||||
if (jumpSong == null) {
|
||||
if (mode == MODE_PLAY_POS_FIRST && j == i) {
|
||||
jumpSong = song;
|
||||
} else if (mode == MODE_PLAY_ID_FIRST || mode == MODE_ENQUEUE_ID_FIRST) {
|
||||
long id;
|
||||
switch (i) {
|
||||
case MediaUtils.TYPE_ARTIST:
|
||||
id = song.artistId;
|
||||
break;
|
||||
case MediaUtils.TYPE_ALBUM:
|
||||
id = song.albumId;
|
||||
break;
|
||||
case MediaUtils.TYPE_SONG:
|
||||
id = song.id;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported id type: " + i);
|
||||
}
|
||||
if (id == l)
|
||||
jumpSong = song;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mShuffleMode != SHUFFLE_NONE)
|
||||
MediaUtils.shuffle(timeline.subList(start, timeline.size()), mShuffleMode == SHUFFLE_ALBUMS);
|
||||
|
||||
if (mode == MODE_PLAY_JUMP_TO && jumpSong != null)
|
||||
mCurrentPos = timeline.indexOf(jumpSong);
|
||||
if (jumpSong != null) {
|
||||
int jumpPos = timeline.indexOf(jumpSong);
|
||||
if (jumpPos != start) {
|
||||
// Get the sublist twice to avoid a ConcurrentModificationException.
|
||||
timeline.addAll(timeline.subList(start, jumpPos));
|
||||
timeline.subList(start, jumpPos).clear();
|
||||
}
|
||||
}
|
||||
|
||||
broadcastChangedSongs();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user