Next/previous album action

This commit is contained in:
Christopher Eby 2011-11-26 20:32:24 -06:00
parent 731b7afed3
commit 61b1d9c5fa
7 changed files with 117 additions and 80 deletions

View File

@ -194,6 +194,8 @@ THE SOFTWARE.
<string name="play_pause">Play/Pause</string> <string name="play_pause">Play/Pause</string>
<string name="next_song">Next song</string> <string name="next_song">Next song</string>
<string name="previous_song">Previous song</string> <string name="previous_song">Previous song</string>
<string name="next_album">Next album</string>
<string name="previous_album">Previous album</string>
<string name="cycle_repeat_mode">Cycle repeat mode</string> <string name="cycle_repeat_mode">Cycle repeat mode</string>
<string name="cycle_shuffle_mode">Cycle shuffle mode</string> <string name="cycle_shuffle_mode">Cycle shuffle mode</string>
<string name="enqueue_current_album">Enqueue current album</string> <string name="enqueue_current_album">Enqueue current album</string>

View File

@ -55,6 +55,8 @@ THE SOFTWARE.
<item>PlayPause</item> <item>PlayPause</item>
<item>NextSong</item> <item>NextSong</item>
<item>PreviousSong</item> <item>PreviousSong</item>
<item>NextAlbum</item>
<item>PreviousAlbum</item>
<item>Repeat</item> <item>Repeat</item>
<item>Shuffle</item> <item>Shuffle</item>
<item>EnqueueAlbum</item> <item>EnqueueAlbum</item>
@ -70,6 +72,8 @@ THE SOFTWARE.
<item>@string/play_pause</item> <item>@string/play_pause</item>
<item>@string/next_song</item> <item>@string/next_song</item>
<item>@string/previous_song</item> <item>@string/previous_song</item>
<item>@string/next_album</item>
<item>@string/previous_album</item>
<item>@string/cycle_repeat_mode</item> <item>@string/cycle_repeat_mode</item>
<item>@string/cycle_shuffle_mode</item> <item>@string/cycle_shuffle_mode</item>
<item>@string/enqueue_current_album</item> <item>@string/enqueue_current_album</item>

View File

@ -65,13 +65,11 @@ public final class CoverView extends View implements Handler.Callback {
*/ */
public interface Callback { public interface Callback {
/** /**
* Called after the view has scrolled to the next (right) cover. * Called after the view has scrolled to the next or previous cover.
*
* @param delta -1 for the previous cover, 1 for the next.
*/ */
public void nextSong(); public void shiftCurrentSong(int delta);
/**
* Called after the view has scrolled to the previous (left) cover.
*/
public void previousSong();
/** /**
* Called when the user has swiped up on the view. * Called when the user has swiped up on the view.
*/ */
@ -422,6 +420,7 @@ public final class CoverView extends View implements Handler.Callback {
*/ */
private static final int MSG_SCROLL = 3; private static final int MSG_SCROLL = 3;
@Override
public boolean handleMessage(Message message) public boolean handleMessage(Message message)
{ {
switch (message.what) { switch (message.what) {
@ -446,12 +445,8 @@ public final class CoverView extends View implements Handler.Callback {
invalidateCovers(); invalidateCovers();
mUiHandler.sendEmptyMessage(MSG_SCROLL); mUiHandler.sendEmptyMessage(MSG_SCROLL);
} else if (mTentativeCover != -1) { } else if (mTentativeCover != -1) {
int delta = mTentativeCover - 1; mCallback.shiftCurrentSong(mTentativeCover - 1);
mTentativeCover = -1; mTentativeCover = -1;
if (delta == 1)
mCallback.nextSong();
else
mCallback.previousSong();
resetScroll(); resetScroll();
} }
break; break;

View File

@ -314,11 +314,11 @@ public class FullPlaybackActivity extends PlaybackActivity
{ {
switch (keyCode) { switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_RIGHT: case KeyEvent.KEYCODE_DPAD_RIGHT:
nextSong(); shiftCurrentSong(SongTimeline.SHIFT_NEXT_SONG);
findViewById(R.id.next).requestFocus(); findViewById(R.id.next).requestFocus();
return true; return true;
case KeyEvent.KEYCODE_DPAD_LEFT: case KeyEvent.KEYCODE_DPAD_LEFT:
previousSong(); shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_SONG);
findViewById(R.id.previous).requestFocus(); findViewById(R.id.previous).requestFocus();
return true; return true;
} }

View File

@ -58,6 +58,8 @@ public class PlaybackActivity extends Activity
PlayPause, PlayPause,
NextSong, NextSong,
PreviousSong, PreviousSong,
NextAlbum,
PreviousAlbum,
Repeat, Repeat,
Shuffle, Shuffle,
EnqueueAlbum, EnqueueAlbum,
@ -199,15 +201,9 @@ public class PlaybackActivity extends Activity
} }
@Override @Override
public void nextSong() public void shiftCurrentSong(int delta)
{ {
setSong(PlaybackService.get(this).nextSong()); setSong(PlaybackService.get(this).shiftCurrentSong(delta));
}
@Override
public void previousSong()
{
setSong(PlaybackService.get(this).previousSong());
} }
public void playPause() public void playPause()
@ -224,13 +220,13 @@ public class PlaybackActivity extends Activity
{ {
switch (view.getId()) { switch (view.getId()) {
case R.id.next: case R.id.next:
nextSong(); shiftCurrentSong(SongTimeline.SHIFT_NEXT_SONG);
break; break;
case R.id.play_pause: case R.id.play_pause:
playPause(); playPause();
break; break;
case R.id.previous: case R.id.previous:
previousSong(); shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_SONG);
break; break;
case R.id.end_action: case R.id.end_action:
cycleFinishAction(); cycleFinishAction();
@ -427,10 +423,16 @@ public class PlaybackActivity extends Activity
playPause(); playPause();
break; break;
case NextSong: case NextSong:
nextSong(); shiftCurrentSong(SongTimeline.SHIFT_NEXT_SONG);
break; break;
case PreviousSong: case PreviousSong:
previousSong(); shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_SONG);
break;
case NextAlbum:
shiftCurrentSong(SongTimeline.SHIFT_NEXT_ALBUM);
break;
case PreviousAlbum:
shiftCurrentSong(SongTimeline.SHIFT_PREVIOUS_ALBUM);
break; break;
case Repeat: case Repeat:
cycleFinishAction(); cycleFinishAction();

View File

@ -748,8 +748,11 @@ public final class PlaybackService extends Service
} }
/** /**
* Move <code>delta</code> places away from the current song. * Move to the next or previous song or album in the timeline.
* *
* @param delta One of SongTimeline.SHIFT_*. 0 can also be passed to
* initialize the current song with media player, notification,
* broadcasts, etc.
* @return The new current song * @return The new current song
*/ */
private Song setCurrentSong(int delta) private Song setCurrentSong(int delta)
@ -760,7 +763,11 @@ public final class PlaybackService extends Service
if (mMediaPlayer.isPlaying()) if (mMediaPlayer.isPlaying())
mMediaPlayer.stop(); mMediaPlayer.stop();
Song song = mTimeline.shiftCurrentSong(delta); Song song;
if (delta == 0)
song = mTimeline.getSong(0);
else
song = mTimeline.shiftCurrentSong(delta);
mCurrentSong = song; mCurrentSong = song;
if (song == null || song.id == -1 || song.path == null) { if (song == null || song.id == -1 || song.path == null) {
if (MediaUtils.isSongAvailable(getContentResolver())) { if (MediaUtils.isSongAvailable(getContentResolver())) {
@ -1115,21 +1122,14 @@ public final class PlaybackService extends Service
} }
/** /**
* Move to the next song in the queue. * Move to next or previous song or album in the queue.
*
* @param delta One of SongTimeline.SHIFT_*.
* @return The new current song.
*/ */
public Song nextSong() public Song shiftCurrentSong(int delta)
{ {
Song song = setCurrentSong(+1); Song song = setCurrentSong(delta);
userActionTriggered();
return song;
}
/**
* Move to the previous song in the queue.
*/
public Song previousSong()
{
Song song = setCurrentSong(-1);
userActionTriggered(); userActionTriggered();
return song; return song;
} }

View File

@ -176,6 +176,30 @@ public final class SongTimeline {
public static final int[] SHUFFLE_ICONS = public static final int[] SHUFFLE_ICONS =
{ R.drawable.shuffle_inactive, R.drawable.shuffle_active, R.drawable.shuffle_album_active }; { R.drawable.shuffle_inactive, R.drawable.shuffle_active, R.drawable.shuffle_album_active };
/**
* Move current position to the previous album.
*
* @see SongTimeline#shiftCurrentSong(int)
*/
public static final int SHIFT_PREVIOUS_ALBUM = -2;
/**
* Move current position to the previous song.
*
* @see SongTimeline#shiftCurrentSong(int)
*/
public static final int SHIFT_PREVIOUS_SONG = -1;
/**
* Move current position to the next song.
*
* @see SongTimeline#shiftCurrentSong(int)
*/
public static final int SHIFT_NEXT_SONG = 1;
/**
* Move current position to the next album.
*
* @see SongTimeline#shiftCurrentSong(int)
*/
public static final int SHIFT_NEXT_ALBUM = 2;
private final Context mContext; private final Context mContext;
/** /**
@ -473,11 +497,12 @@ public final class SongTimeline {
} else if (pos > size) { } else if (pos > size) {
return null; return null;
} else if (pos == size) { } else if (pos == size) {
switch (mFinishAction) { if (mFinishAction == FINISH_RANDOM) {
case FINISH_STOP: song = MediaUtils.randomSong(mContext.getContentResolver());
case FINISH_REPEAT: if (song == null)
case FINISH_REPEAT_CURRENT: return null;
case FINISH_STOP_CURRENT: timeline.add(song);
} else {
if (size == 0) if (size == 0)
// empty queue // empty queue
return null; return null;
@ -485,15 +510,6 @@ public final class SongTimeline {
song = shuffleAll(); song = shuffleAll();
else else
song = timeline.get(0); song = timeline.get(0);
break;
case FINISH_RANDOM:
song = MediaUtils.randomSong(mContext.getContentResolver());
if (song == null)
return null;
timeline.add(song);
break;
default:
throw new IllegalStateException("Invalid finish action: " + mFinishAction);
} }
} else { } else {
song = timeline.get(pos); song = timeline.get(pos);
@ -508,40 +524,58 @@ public final class SongTimeline {
} }
/** /**
* Shift the current song by <code>delta</code> places. * Internal implementation for shiftCurrentSong. Does all the work except
* broadcasting the timeline change: updates mCurrentPos and handles
* shuffling, repeating, and random mode.
* *
* @param delta The delta. Must be -1, 0, 1. * @param delta -1 to move to the previous song or 1 for the next.
*/
private void shiftCurrentSongInternal(int delta)
{
int pos = mCurrentPos + delta;
if (mFinishAction != FINISH_RANDOM && pos == mSongs.size()) {
if (mShuffleMode != SHUFFLE_NONE && !mSongs.isEmpty()) {
if (mShuffledSongs == null)
shuffleAll();
mSongs = mShuffledSongs;
}
pos = 0;
} else if (pos < 0) {
if (mFinishAction == FINISH_RANDOM)
pos = 0;
else
pos = Math.max(0, mSongs.size() - 1);
}
mCurrentPos = pos;
mShuffledSongs = null;
}
/**
* Move to the next or previous song or album.
*
* @param delta One of SongTimeline.SHIFT_*.
* @return The Song at the new position * @return The Song at the new position
*/ */
public Song shiftCurrentSong(int delta) public Song shiftCurrentSong(int delta)
{ {
Assert.assertTrue(delta >= -1 && delta <= 1);
synchronized (this) { synchronized (this) {
int pos = mCurrentPos + delta; if (delta == SHIFT_PREVIOUS_SONG || delta == SHIFT_NEXT_SONG) {
shiftCurrentSongInternal(delta);
if (mFinishAction != FINISH_RANDOM && pos == mSongs.size()) { } else {
if (mShuffleMode != SHUFFLE_NONE && !mSongs.isEmpty()) { Song song = getSong(0);
if (mShuffledSongs == null) long currentAlbum = song.albumId;
shuffleAll(); long currentSong = song.id;
mSongs = mShuffledSongs; delta = delta > 0 ? 1 : -1;
} do {
shiftCurrentSongInternal(delta);
pos = 0; song = getSong(0);
} else if (pos < 0) { } while (currentAlbum == song.albumId && currentSong != song.id);
if (mFinishAction == FINISH_RANDOM)
pos = 0;
else
pos = Math.max(0, mSongs.size() - 1);
} }
mCurrentPos = pos;
mShuffledSongs = null;
} }
changed();
if (delta != 0)
changed();
return getSong(0); return getSong(0);
} }