diff --git a/api/current.txt b/api/current.txt index 64838a4ef0533..98af525f5f0ed 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22572,8 +22572,10 @@ package android.media.session { method public java.util.List getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); + method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); + method public boolean getShuffleMode(); method public android.media.session.MediaController.TransportControls getTransportControls(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); @@ -22590,8 +22592,10 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List); method public void onQueueTitleChanged(java.lang.CharSequence); + method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); + method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -22620,6 +22624,8 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); + method public void setRepeatMode(int); + method public void setShuffleMode(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -22646,7 +22652,9 @@ package android.media.session { method public void setQueue(java.util.List); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); + method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); + method public void setShuffleMode(boolean); field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } @@ -22669,6 +22677,8 @@ package android.media.session { method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); + method public void onSetRepeatMode(int); + method public void onSetShuffleMode(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -22729,12 +22739,17 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L + field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L + field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL + field public static final int REPEAT_MODE_ALL = 2; // 0x2 + field public static final int REPEAT_MODE_NONE = 0; // 0x0 + field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 diff --git a/api/system-current.txt b/api/system-current.txt index c7a05b2cd826f..0ddcb51c82d18 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -24158,8 +24158,10 @@ package android.media.session { method public java.util.List getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); + method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); + method public boolean getShuffleMode(); method public android.media.session.MediaController.TransportControls getTransportControls(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); @@ -24176,8 +24178,10 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List); method public void onQueueTitleChanged(java.lang.CharSequence); + method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); + method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -24206,6 +24210,8 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); + method public void setRepeatMode(int); + method public void setShuffleMode(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -24232,7 +24238,9 @@ package android.media.session { method public void setQueue(java.util.List); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); + method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); + method public void setShuffleMode(boolean); field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } @@ -24255,6 +24263,8 @@ package android.media.session { method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); + method public void onSetRepeatMode(int); + method public void onSetShuffleMode(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -24315,12 +24325,17 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L + field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L + field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL + field public static final int REPEAT_MODE_ALL = 2; // 0x2 + field public static final int REPEAT_MODE_NONE = 0; // 0x0 + field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 diff --git a/api/test-current.txt b/api/test-current.txt index 881d290536c52..4e62c1668271f 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -22642,8 +22642,10 @@ package android.media.session { method public java.util.List getQueue(); method public java.lang.CharSequence getQueueTitle(); method public int getRatingType(); + method public int getRepeatMode(); method public android.app.PendingIntent getSessionActivity(); method public android.media.session.MediaSession.Token getSessionToken(); + method public boolean getShuffleMode(); method public android.media.session.MediaController.TransportControls getTransportControls(); method public void registerCallback(android.media.session.MediaController.Callback); method public void registerCallback(android.media.session.MediaController.Callback, android.os.Handler); @@ -22660,8 +22662,10 @@ package android.media.session { method public void onPlaybackStateChanged(android.media.session.PlaybackState); method public void onQueueChanged(java.util.List); method public void onQueueTitleChanged(java.lang.CharSequence); + method public void onRepeatModeChanged(int); method public void onSessionDestroyed(); method public void onSessionEvent(java.lang.String, android.os.Bundle); + method public void onShuffleModeChanged(boolean); } public static final class MediaController.PlaybackInfo { @@ -22690,6 +22694,8 @@ package android.media.session { method public void sendCustomAction(android.media.session.PlaybackState.CustomAction, android.os.Bundle); method public void sendCustomAction(java.lang.String, android.os.Bundle); method public void setRating(android.media.Rating); + method public void setRepeatMode(int); + method public void setShuffleMode(boolean); method public void skipToNext(); method public void skipToPrevious(); method public void skipToQueueItem(long); @@ -22716,7 +22722,9 @@ package android.media.session { method public void setQueue(java.util.List); method public void setQueueTitle(java.lang.CharSequence); method public void setRatingType(int); + method public void setRepeatMode(int); method public void setSessionActivity(android.app.PendingIntent); + method public void setShuffleMode(boolean); field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1 field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2 } @@ -22739,6 +22747,8 @@ package android.media.session { method public void onRewind(); method public void onSeekTo(long); method public void onSetRating(android.media.Rating); + method public void onSetRepeatMode(int); + method public void onSetShuffleMode(boolean); method public void onSkipToNext(); method public void onSkipToPrevious(); method public void onSkipToQueueItem(long); @@ -22799,12 +22809,17 @@ package android.media.session { field public static final long ACTION_REWIND = 8L; // 0x8L field public static final long ACTION_SEEK_TO = 256L; // 0x100L field public static final long ACTION_SET_RATING = 128L; // 0x80L + field public static final long ACTION_SET_REPEAT_MODE = 262144L; // 0x40000L + field public static final long ACTION_SET_SHUFFLE_MODE = 524288L; // 0x80000L field public static final long ACTION_SKIP_TO_NEXT = 32L; // 0x20L field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L field public static final android.os.Parcelable.Creator CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL + field public static final int REPEAT_MODE_ALL = 2; // 0x2 + field public static final int REPEAT_MODE_NONE = 0; // 0x0 + field public static final int REPEAT_MODE_ONE = 1; // 0x1 field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 field public static final int STATE_ERROR = 7; // 0x7 diff --git a/cmds/media/src/com/android/commands/media/Media.java b/cmds/media/src/com/android/commands/media/Media.java index d7f23cb440989..2e9d0d68fafb2 100644 --- a/cmds/media/src/com/android/commands/media/Media.java +++ b/cmds/media/src/com/android/commands/media/Media.java @@ -57,6 +57,7 @@ public class Media extends BaseCommand { (new Media()).run(args); } + @Override public void onShowUsage(PrintStream out) { out.println( "usage: media [subcommand] [options]\n" + @@ -73,6 +74,7 @@ public class Media extends BaseCommand { ); } + @Override public void onRun() throws Exception { mSessionService = ISessionManager.Stub.asInterface(ServiceManager.checkService( Context.MEDIA_SESSION_SERVICE)); @@ -222,6 +224,16 @@ public class Media extends BaseCommand { System.out.println("onVolumeInfoChanged " + info); } + @Override + public void onRepeatModeChanged(int repeatMode) throws RemoteException { + System.out.println("onRepeatModeChanged " + repeatMode); + } + + @Override + public void onShuffleModeChanged(boolean shuffleMode) throws RemoteException { + System.out.println("onShuffleModeChanged " + shuffleMode); + } + void printUsageMessage() { try { System.out.println("V2Monitoring session " + mController.getTag() diff --git a/media/java/android/media/session/ISession.aidl b/media/java/android/media/session/ISession.aidl index 3affee5c0aa79..a2154936ed811 100644 --- a/media/java/android/media/session/ISession.aidl +++ b/media/java/android/media/session/ISession.aidl @@ -45,6 +45,8 @@ interface ISession { void setQueueTitle(CharSequence title); void setExtras(in Bundle extras); void setRatingType(int type); + void setRepeatMode(int repeatMode); + void setShuffleMode(boolean shuffleMode); // These commands relate to volume handling void setPlaybackToLocal(in AudioAttributes attributes); diff --git a/media/java/android/media/session/ISessionCallback.aidl b/media/java/android/media/session/ISessionCallback.aidl index 893bd3c8cbb13..b3c6d59d7f8aa 100644 --- a/media/java/android/media/session/ISessionCallback.aidl +++ b/media/java/android/media/session/ISessionCallback.aidl @@ -46,6 +46,8 @@ oneway interface ISessionCallback { void onRewind(); void onSeekTo(long pos); void onRate(in Rating rating); + void onRepeatMode(int repeatMode); + void onShuffleMode(boolean shuffleMode); void onCustomAction(String action, in Bundle args); // These callbacks are for volume handling diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl index 249bcdc802cea..b73f167d4acc7 100644 --- a/media/java/android/media/session/ISessionController.aidl +++ b/media/java/android/media/session/ISessionController.aidl @@ -48,6 +48,14 @@ interface ISessionController { ParcelableVolumeInfo getVolumeAttributes(); void adjustVolume(int direction, int flags, String packageName); void setVolumeTo(int value, int flags, String packageName); + MediaMetadata getMetadata(); + PlaybackState getPlaybackState(); + ParceledListSlice getQueue(); + CharSequence getQueueTitle(); + Bundle getExtras(); + int getRatingType(); + int getRepeatMode(); + boolean getShuffleMode(); // These commands are for the TransportControls void prepare(); @@ -67,11 +75,7 @@ interface ISessionController { void rewind(); void seekTo(long pos); void rate(in Rating rating); + void repeatMode(int repeatMode); + void shuffleMode(boolean shuffleMode); void sendCustomAction(String action, in Bundle args); - MediaMetadata getMetadata(); - PlaybackState getPlaybackState(); - ParceledListSlice getQueue(); - CharSequence getQueueTitle(); - Bundle getExtras(); - int getRatingType(); } diff --git a/media/java/android/media/session/ISessionControllerCallback.aidl b/media/java/android/media/session/ISessionControllerCallback.aidl index cf3176706d7ed..9517c088bcf35 100644 --- a/media/java/android/media/session/ISessionControllerCallback.aidl +++ b/media/java/android/media/session/ISessionControllerCallback.aidl @@ -36,4 +36,6 @@ oneway interface ISessionControllerCallback { void onQueueTitleChanged(CharSequence title); void onExtrasChanged(in Bundle extras); void onVolumeInfoChanged(in ParcelableVolumeInfo info); + void onRepeatModeChanged(int repeatMode); + void onShuffleModeChanged(boolean shuffleMode); } diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java index 622900f5c7f94..ddff1b7a1bc58 100644 --- a/media/java/android/media/session/MediaController.java +++ b/media/java/android/media/session/MediaController.java @@ -63,7 +63,9 @@ public final class MediaController { private static final int MSG_UPDATE_QUEUE = 5; private static final int MSG_UPDATE_QUEUE_TITLE = 6; private static final int MSG_UPDATE_EXTRAS = 7; - private static final int MSG_DESTROYED = 8; + private static final int MSG_UPDATE_REPEAT_MODE = 8; + private static final int MSG_UPDATE_SHUFFLE_MODE = 9; + private static final int MSG_DESTROYED = 10; private final ISessionController mSessionBinder; @@ -233,6 +235,35 @@ public final class MediaController { } } + /** + * Get the repeat mode for this session. + * + * @return The latest repeat mode set to the session, or + * {@link PlaybackState#REPEAT_MODE_NONE} if not set. + */ + public int getRepeatMode() { + try { + return mSessionBinder.getRepeatMode(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getRepeatMode.", e); + return PlaybackState.REPEAT_MODE_NONE; + } + } + + /** + * Get the shuffle mode for this session. + * + * @return The latest shuffle mode set to the session, or false if not set. + */ + public boolean getShuffleMode() { + try { + return mSessionBinder.getShuffleMode(); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling getShuffleMode.", e); + return false; + } + } + /** * Get the flags for this session. Flags are defined in {@link MediaSession}. * @@ -579,6 +610,26 @@ public final class MediaController { */ public void onAudioInfoChanged(PlaybackInfo info) { } + + /** + * Override to handle changes to the repeat mode. + * + * @param repeatMode The repeat mode. It should be one of followings: + * {@link PlaybackState#REPEAT_MODE_NONE}, + * {@link PlaybackState#REPEAT_MODE_ONE}, + * {@link PlaybackState#REPEAT_MODE_ALL} + */ + public void onRepeatModeChanged(@PlaybackState.RepeatMode int repeatMode) { + } + + /** + * Override to handle changes to the shuffle mode. + * + * @param shuffleMode The shuffle mode. {@code true} if _the_ shuffle mode is on, + * {@code false} otherwise. + */ + public void onShuffleModeChanged(boolean shuffleMode) { + } } /** @@ -861,6 +912,35 @@ public final class MediaController { } } + /** + * Set the repeat mode for this session. + * + * @param repeatMode The repeat mode. Must be one of the followings: + * {@link PlaybackState#REPEAT_MODE_NONE}, + * {@link PlaybackState#REPEAT_MODE_ONE}, + * {@link PlaybackState#REPEAT_MODE_ALL} + */ + public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) { + try { + mSessionBinder.repeatMode(repeatMode); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling setRepeatMode.", e); + } + } + + /** + * Set the shuffle mode for this session. + * + * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise. + */ + public void setShuffleMode(boolean shuffleMode) { + try { + mSessionBinder.shuffleMode(shuffleMode); + } catch (RemoteException e) { + Log.wtf(TAG, "Error calling shuffleQueue.", e); + } + } + /** * Send a custom action back for the {@link MediaSession} to perform. * @@ -1062,6 +1142,21 @@ public final class MediaController { } } + @Override + public void onRepeatModeChanged(int repeatMode) { + MediaController controller = mController.get(); + if (controller != null) { + controller.postMessage(MSG_UPDATE_REPEAT_MODE, repeatMode, null); + } + } + + @Override + public void onShuffleModeChanged(boolean shuffleMode) { + MediaController controller = mController.get(); + if (controller != null) { + controller.postMessage(MSG_UPDATE_SHUFFLE_MODE, shuffleMode, null); + } + } } private final static class MessageHandler extends Handler { @@ -1100,6 +1195,12 @@ public final class MediaController { case MSG_UPDATE_VOLUME: mCallback.onAudioInfoChanged((PlaybackInfo) msg.obj); break; + case MSG_UPDATE_REPEAT_MODE: + mCallback.onRepeatModeChanged((int) msg.obj); + break; + case MSG_UPDATE_SHUFFLE_MODE: + mCallback.onShuffleModeChanged((boolean) msg.obj); + break; case MSG_DESTROYED: mCallback.onSessionDestroyed(); break; diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java index 0959961321922..cab5d93802ed7 100644 --- a/media/java/android/media/session/MediaSession.java +++ b/media/java/android/media/session/MediaSession.java @@ -479,6 +479,41 @@ public final class MediaSession { } } + /** + * Set the repeat mode for this session. + *

+ * Note that if this method is not called before, {@link MediaController#getRepeatMode} + * will return {@link PlaybackState#REPEAT_MODE_NONE}. + * + * @param repeatMode The repeat mode. Must be one of the followings: + * {@link PlaybackState#REPEAT_MODE_NONE}, + * {@link PlaybackState#REPEAT_MODE_ONE}, + * {@link PlaybackState#REPEAT_MODE_ALL} + */ + public void setRepeatMode(@PlaybackState.RepeatMode int repeatMode) { + try { + mBinder.setRepeatMode(repeatMode); + } catch (RemoteException e) { + Log.e(TAG, "Error in setRepeatMode.", e); + } + } + + /** + * Set the shuffle mode for this session. + *

+ * Note that if this method is not called before, {@link MediaController#getShuffleMode} + * will return {@code false}. + * + * @param shuffleMode {@code true} if the shuffle mode is on, {@code false} otherwise. + */ + public void setShuffleMode(boolean shuffleMode) { + try { + mBinder.setShuffleMode(shuffleMode); + } catch (RemoteException e) { + Log.e(TAG, "Error in setShuffleMode.", e); + } + } + /** * Set some extras that can be associated with the {@link MediaSession}. No assumptions should * be made as to how a {@link MediaController} will handle these extras. @@ -598,6 +633,14 @@ public final class MediaSession { postToCallback(CallbackMessageHandler.MSG_RATE, rating); } + private void dispatchRepeatMode(int repeatMode) { + postToCallback(CallbackMessageHandler.MSG_REPEAT_MODE, repeatMode); + } + + private void dispatchShuffleMode(boolean shuffleMode) { + postToCallback(CallbackMessageHandler.MSG_SHUFFLE_MODE, shuffleMode); + } + private void dispatchCustomAction(String action, Bundle args) { postToCallback(CallbackMessageHandler.MSG_CUSTOM_ACTION, action, args); } @@ -963,6 +1006,33 @@ public final class MediaSession { public void onSetRating(@NonNull Rating rating) { } + /** + * Override to handle the setting of the repeat mode. + *

+ * You should call {@link #setRepeatMode} before end of this method in order to notify + * the change to the {@link MediaController}, or {@link MediaController#getRepeatMode} + * could return an invalid value. + * + * @param repeatMode The repeat mode which is one of followings: + * {@link PlaybackState#REPEAT_MODE_NONE}, + * {@link PlaybackState#REPEAT_MODE_ONE}, + * {@link PlaybackState#REPEAT_MODE_ALL} + */ + public void onSetRepeatMode(@PlaybackState.RepeatMode int repeatMode) { + } + + /** + * Override to handle the setting of the shuffle mode. + *

+ * You should call {@link #setShuffleMode} before end of this method in order to notify + * the change to the {@link MediaController}, or {@link MediaController#getShuffleMode} + * could return an invalid value. + * + * @param shuffleMode true if the shuffle mode is on, false otherwise. + */ + public void onSetShuffleMode(boolean shuffleMode) { + } + /** * Called when a {@link MediaController} wants a {@link PlaybackState.CustomAction} to be * performed. @@ -1144,6 +1214,22 @@ public final class MediaSession { } } + @Override + public void onRepeatMode(int repeatMode) { + MediaSession session = mMediaSession.get(); + if (session != null) { + session.dispatchRepeatMode(repeatMode); + } + } + + @Override + public void onShuffleMode(boolean shuffleMode) { + MediaSession session = mMediaSession.get(); + if (session != null) { + session.dispatchShuffleMode(shuffleMode); + } + } + @Override public void onCustomAction(String action, Bundle args) { MediaSession session = mMediaSession.get(); @@ -1285,9 +1371,11 @@ public final class MediaSession { private static final int MSG_REWIND = 17; private static final int MSG_SEEK_TO = 18; private static final int MSG_RATE = 19; - private static final int MSG_CUSTOM_ACTION = 20; - private static final int MSG_ADJUST_VOLUME = 21; - private static final int MSG_SET_VOLUME = 22; + private static final int MSG_REPEAT_MODE = 20; + private static final int MSG_SHUFFLE_MODE = 21; + private static final int MSG_CUSTOM_ACTION = 22; + private static final int MSG_ADJUST_VOLUME = 23; + private static final int MSG_SET_VOLUME = 24; private MediaSession.Callback mCallback; @@ -1376,6 +1464,12 @@ public final class MediaSession { case MSG_RATE: mCallback.onSetRating((Rating) msg.obj); break; + case MSG_REPEAT_MODE: + mCallback.onSetRepeatMode((int) msg.obj); + break; + case MSG_SHUFFLE_MODE: + mCallback.onSetShuffleMode((boolean) msg.obj); + break; case MSG_CUSTOM_ACTION: mCallback.onCustomAction((String) msg.obj, msg.getData()); break; diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java index 8283c8b967e80..5cdd201db26da 100644 --- a/media/java/android/media/session/PlaybackState.java +++ b/media/java/android/media/session/PlaybackState.java @@ -45,7 +45,8 @@ public final class PlaybackState implements Parcelable { ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING, ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH, ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE, - ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI}) + ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI, + ACTION_SET_REPEAT_MODE, ACTION_SET_SHUFFLE_MODE}) @Retention(RetentionPolicy.SOURCE) public @interface Actions {} @@ -175,6 +176,20 @@ public final class PlaybackState implements Parcelable { */ public static final long ACTION_PREPARE_FROM_URI = 1 << 17; + /** + * Indicates this session supports the set repeat mode command. + * + * @see Builder#setActions(long) + */ + public static final long ACTION_SET_REPEAT_MODE = 1 << 18; + + /** + * Indicates this session supports the set shuffle mode command. + * + * @see Builder#setActions(long) + */ + public static final long ACTION_SET_SHUFFLE_MODE = 1 << 19; + /** * @hide */ @@ -281,6 +296,30 @@ public final class PlaybackState implements Parcelable { */ public final static long PLAYBACK_POSITION_UNKNOWN = -1; + /** + * @hide + */ + @IntDef({REPEAT_MODE_NONE, REPEAT_MODE_ONE, REPEAT_MODE_ALL}) + @Retention(RetentionPolicy.SOURCE) + public @interface RepeatMode {} + /** + * Use this value with {@link MediaController.TransportControls#setRepeatMode} + * to indicate that the playback will be stopped at the end of the playing media list. + */ + public final static int REPEAT_MODE_NONE = 0; + + /** + * Use this value with {@link MediaController.TransportControls#setRepeatMode} + * to indicate that the playback of the current playing media item will be repeated. + */ + public final static int REPEAT_MODE_ONE = 1; + + /** + * Use this value with {@link MediaController.TransportControls#setRepeatMode} + * to indicate that the playback of the playing media list will be repeated. + */ + public final static int REPEAT_MODE_ALL = 2; + private final int mState; private final long mPosition; private final long mBufferedPosition; @@ -427,6 +466,8 @@ public final class PlaybackState implements Parcelable { *

  • {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}
  • *
  • {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}
  • *
  • {@link PlaybackState#ACTION_PREPARE_FROM_URI}
  • + *
  • {@link PlaybackState#ACTION_SET_REPEAT_MODE}
  • + *
  • {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}
  • * */ @Actions @@ -961,6 +1002,8 @@ public final class PlaybackState implements Parcelable { *
  • {@link PlaybackState#ACTION_PREPARE_FROM_MEDIA_ID}
  • *
  • {@link PlaybackState#ACTION_PREPARE_FROM_SEARCH}
  • *
  • {@link PlaybackState#ACTION_PREPARE_FROM_URI}
  • + *
  • {@link PlaybackState#ACTION_SET_REPEAT_MODE}
  • + *
  • {@link PlaybackState#ACTION_SET_SHUFFLE_MODE}
  • * * * @param actions The set of actions allowed. diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index 88d6c14fb5dea..2d71ce9902031 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -107,6 +107,8 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private ParceledListSlice mQueue; private CharSequence mQueueTitle; private int mRatingType; + private int mRepeatMode; + private boolean mShuffleMode; private long mLastActiveTime; // End TransportPerformer fields @@ -620,6 +622,44 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } + private void pushRepeatModeUpdate() { + synchronized (mLock) { + if (mDestroyed) { + return; + } + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + ISessionControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onRepeatModeChanged(mRepeatMode); + } catch (DeadObjectException e) { + mControllerCallbacks.remove(i); + Log.w(TAG, "Removed dead callback in pushRepeatModeUpdate.", e); + } catch (RemoteException e) { + Log.w(TAG, "unexpected exception in pushRepeatModeUpdate.", e); + } + } + } + } + + private void pushShuffleModeUpdate() { + synchronized (mLock) { + if (mDestroyed) { + return; + } + for (int i = mControllerCallbacks.size() - 1; i >= 0; i--) { + ISessionControllerCallback cb = mControllerCallbacks.get(i); + try { + cb.onShuffleModeChanged(mShuffleMode); + } catch (DeadObjectException e) { + mControllerCallbacks.remove(i); + Log.w(TAG, "Removed dead callback in pushShuffleModeUpdate.", e); + } catch (RemoteException e) { + Log.w(TAG, "unexpected exception in pushShuffleModeUpdate.", e); + } + } + } + } + private void pushSessionDestroyed() { synchronized (mLock) { // This is the only method that may be (and can only be) called @@ -827,6 +867,30 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mRatingType = type; } + @Override + public void setRepeatMode(int repeatMode) { + boolean changed; + synchronized (mLock) { + changed = mRepeatMode != repeatMode; + mRepeatMode = repeatMode; + } + if (changed) { + mHandler.post(MessageHandler.MSG_UPDATE_REPEAT_MODE); + } + } + + @Override + public void setShuffleMode(boolean shuffleMode) { + boolean changed; + synchronized (mLock) { + changed = mShuffleMode != shuffleMode; + mShuffleMode = shuffleMode; + } + if (changed) { + mHandler.post(MessageHandler.MSG_UPDATE_SHUFFLE_MODE); + } + } + @Override public void setCurrentVolume(int volume) { mCurrentVolume = volume; @@ -1043,6 +1107,22 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } } + public void repeatMode(int repeatMode) { + try { + mCb.onRepeatMode(repeatMode); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in repeatMode.", e); + } + } + + public void shuffleMode(boolean shuffleMode) { + try { + mCb.onShuffleMode(shuffleMode); + } catch (RemoteException e) { + Slog.e(TAG, "Remote failure in shuffleMode.", e); + } + } + public void adjustVolume(int direction) { try { mCb.onAdjustVolume(direction); @@ -1277,6 +1357,19 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mSessionCb.rate(rating); } + @Override + public void repeatMode(int repeatMode) { + updateCallingPackage(); + mSessionCb.repeatMode(repeatMode); + } + + @Override + public void shuffleMode(boolean shuffleMode) throws RemoteException { + updateCallingPackage(); + mSessionCb.shuffleMode(shuffleMode); + } + + @Override public void sendCustomAction(String action, Bundle args) throws RemoteException { @@ -1284,7 +1377,6 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { mSessionCb.sendCustomAction(action, args); } - @Override public MediaMetadata getMetadata() { synchronized (mLock) { @@ -1321,6 +1413,16 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return mRatingType; } + @Override + public int getRepeatMode() { + return mRepeatMode; + } + + @Override + public boolean getShuffleMode() { + return mShuffleMode; + } + @Override public boolean isTransportControlEnabled() { return MediaSessionRecord.this.isTransportControlEnabled(); @@ -1336,7 +1438,9 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { private static final int MSG_SEND_EVENT = 6; private static final int MSG_UPDATE_SESSION_STATE = 7; private static final int MSG_UPDATE_VOLUME = 8; - private static final int MSG_DESTROYED = 9; + private static final int MSG_UPDATE_REPEAT_MODE = 9; + private static final int MSG_UPDATE_SHUFFLE_MODE = 10; + private static final int MSG_DESTROYED = 11; public MessageHandler(Looper looper) { super(looper); @@ -1368,6 +1472,12 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { case MSG_UPDATE_VOLUME: pushVolumeUpdate(); break; + case MSG_UPDATE_REPEAT_MODE: + pushRepeatModeUpdate(); + break; + case MSG_UPDATE_SHUFFLE_MODE: + pushShuffleModeUpdate(); + break; case MSG_DESTROYED: pushSessionDestroyed(); }