summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRakesh Iyer <rni@google.com>2016-10-28 16:34:57 -0700
committerRakesh Iyer <rni@google.com>2016-10-31 11:20:48 -0700
commitd47e834a2872587d83e727d8001815476713e297 (patch)
tree09874d8451a8aa5634fa4dae46b2a8f32753ce68
parent7e37ae05a9c7c9ecf8569a5bfe752a54f660a6ba (diff)
downloadLocalMediaPlayer-d47e834a2872587d83e727d8001815476713e297.tar.gz
Implement shuffle in local media player.
This change adds in a shuffle custom action for the local media player. The shuffle algorithm itself is pretty naive it just removes the current playing item from the list, shuffles the rest and puts the current item back on front of the list. Bug: 398865 Test: Manual. Change-Id: Idcdf2c00e508634de9bfff817d5a562a14cdc675
-rw-r--r--res/drawable/shuffle.xml15
-rw-r--r--res/values/strings.xml2
-rw-r--r--src/com/android/car/media/localmediaplayer/Player.java45
3 files changed, 59 insertions, 3 deletions
diff --git a/res/drawable/shuffle.xml b/res/drawable/shuffle.xml
new file mode 100644
index 0000000..7f9fbff
--- /dev/null
+++ b/res/drawable/shuffle.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48"
+ android:viewportHeight="48">
+
+ <path
+ android:pathData="M0 0h48v48H0z" />
+ <path
+ android:fillColor="#000000"
+ android:pathData="M21.17 18.34L10.83 8 8 10.83l10.34 10.34 2.83-2.83zM29 8l4.09 4.09L8 37.17 10.83
+40l25.09-25.09L40 19V8H29zm.66 18.83l-2.83 2.83 6.26 6.26L29 40h11V29l-4.09
+4.09-6.25-6.26z" />
+</vector>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 0f115f0..0abd1a8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -21,6 +21,6 @@
<string name="genres_title">Genres</string>
<string name="albums_title">Albums</string>
<string name="playback_error">Something went wrong.</string>
- <string name="todo_permissions">TODO: Request sdcard permission here.</string>
<string name="playlist">Now Playing</string>
+ <string name="shuffle">Shuffle</string>
</resources>
diff --git a/src/com/android/car/media/localmediaplayer/Player.java b/src/com/android/car/media/localmediaplayer/Player.java
index 591524f..50ab5df 100644
--- a/src/com/android/car/media/localmediaplayer/Player.java
+++ b/src/com/android/car/media/localmediaplayer/Player.java
@@ -25,10 +25,12 @@ import android.media.MediaPlayer.OnCompletionListener;
import android.media.session.MediaSession;
import android.media.session.MediaSession.QueueItem;
import android.media.session.PlaybackState;
+import android.media.session.PlaybackState.CustomAction;
import android.os.Bundle;
import android.util.Log;
import java.io.IOException;
+import java.util.Collections;
import java.util.List;
/**
@@ -54,11 +56,14 @@ public class Player extends MediaSession.Callback {
| PlaybackState.ACTION_PLAY_FROM_MEDIA_ID | PlaybackState.ACTION_SKIP_TO_NEXT
| PlaybackState.ACTION_SKIP_TO_PREVIOUS;
+ private static final String SHUFFLE = "android.car.media.localmediaplayer.shuffle";
+
private final Context mContext;
private final MediaSession mSession;
private final AudioManager mAudioManager;
private final PlaybackState mErrorState;
private final DataModel mDataModel;
+ private final CustomAction mShuffle;
private List<QueueItem> mQueue;
private int mCurrentQueueIdx = 0;
@@ -66,13 +71,15 @@ public class Player extends MediaSession.Callback {
// TODO: Use multiple media players for gapless playback.
private final MediaPlayer mMediaPlayer;
-
public Player(Context context, MediaSession session, DataModel dataModel) {
mContext = context;
mDataModel = dataModel;
mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
mSession = session;
+ mShuffle = new CustomAction.Builder(SHUFFLE, context.getString(R.string.shuffle),
+ R.drawable.shuffle).build();
+
mMediaPlayer = new MediaPlayer();
mMediaPlayer.reset();
mMediaPlayer.setOnCompletionListener(mOnCompletionListener);
@@ -171,7 +178,8 @@ public class Player extends MediaSession.Callback {
.setState(PlaybackState.STATE_PLAYING,
mMediaPlayer.getCurrentPosition(), PLAYBACK_SPEED)
.setActions(PLAYING_ACTIONS)
- .setActiveQueueItemId(mCurrentQueueIdx)
+ .addCustomAction(mShuffle)
+ .setActiveQueueItemId(mQueue.get(mCurrentQueueIdx).getQueueId())
.build();
mSession.setPlaybackState(state);
}
@@ -190,6 +198,7 @@ public class Player extends MediaSession.Callback {
PlaybackState state = new PlaybackState.Builder()
.setState(PlaybackState.STATE_PAUSED, currentPosition, PLAYBACK_SPEED_STOPPED)
.setActions(PAUSED_ACTIONS)
+ .addCustomAction(mShuffle)
.build();
mSession.setPlaybackState(state);
}
@@ -291,6 +300,25 @@ public class Player extends MediaSession.Callback {
}
}
+ /**
+ * This is a naive implementation of shuffle, previously played songs may repeat after the
+ * shuffle operation. Only call this from the main thread.
+ */
+ private void shuffle() {
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ Log.d(TAG, "Shuffling");
+ }
+
+ if (mQueue != null) {
+ QueueItem current = mQueue.remove(mCurrentQueueIdx);
+ Collections.shuffle(mQueue);
+ mQueue.add(0, current);
+ mCurrentQueueIdx = 0;
+ mSession.setQueue(mQueue);
+ updatePlaybackStatePlaying();
+ }
+ }
+
@Override
public void onPlayFromMediaId(String mediaId, Bundle extras) {
super.onPlayFromMediaId(mediaId, extras);
@@ -341,6 +369,17 @@ public class Player extends MediaSession.Callback {
}
}
+ @Override
+ public void onCustomAction(String action, Bundle extras) {
+ switch (action) {
+ case SHUFFLE:
+ shuffle();
+ break;
+ default:
+ Log.e(TAG, "Unhandled custom action: " + action);
+ }
+ }
+
private OnAudioFocusChangeListener mAudioFocusListener = new OnAudioFocusChangeListener() {
@Override
public void onAudioFocusChange(int focus) {
@@ -353,6 +392,8 @@ public class Player extends MediaSession.Callback {
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
pausePlayback();
break;
+ default:
+ Log.e(TAG, "Unhandled audio focus type: " + focus);
}
}
};